Terminal compatibility batch
- Answer kitty keyboard protocol queries (CSI ?u -> CSI ?0u) and silently accept push/pop/set so clients detect the lack of support without a timeout, and so st stops logging them as unknown sequences. - XTVERSION (CSI >0q) reports st(VERSION). - DECRQM (CSI ?Ps$p / CSI Ps$p) reports the state of the common private and ANSI modes including 2026 (synchronized updates) and 2004. - csiparse() now recognises the >, < and = private prefixes. - New OSC7_OSC8_PATCH: OSC 7 stores the shell's working directory in term.cwd; OSC 8 hyperlinks are stored per cell and, with the openurlonclick patch, are clickable and take precedence over URL text detection. - kitty: Unicode placeholder cells are now blitted from one cached scaled pixmap per virtual placement instead of rescaling every cell on every redraw.
This commit is contained in:
parent
56c4253a87
commit
3a4e096d9b
120
kitty.c
120
kitty.c
@ -2295,122 +2295,46 @@ 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 bx, by;
|
int w, h, bx, by, cw = win.cw, ch = win.ch;
|
||||||
|
int sx, sy, cellw, cellh;
|
||||||
|
|
||||||
if (!im || row >= p->rows || col >= p->cols)
|
if (!p->image || row >= p->rows || col >= p->cols)
|
||||||
|
return;
|
||||||
|
if (!kitty_prepare(p, &w, &h))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fullw = p->cols * cw;
|
sx = col * cw;
|
||||||
fullh = p->rows * ch;
|
sy = row * ch;
|
||||||
if (fullw <= 0 || fullh <= 0)
|
cellw = KMIN(cw, w - sx);
|
||||||
|
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) {
|
||||||
src = XRenderCreatePicture(xw.dpy, pm, fmt, 0, &pa);
|
dstpic = XRenderCreatePicture(xw.dpy, xw.buf, fmt, 0, &pa);
|
||||||
fmt = XRenderFindVisualFormat(xw.dpy, xw.vis);
|
XRenderComposite(xw.dpy, PictOpOver, src, None, dstpic, sx, sy, 0, 0,
|
||||||
if (fmt) {
|
bx + px * cw, by + py * ch, cellw, cellh);
|
||||||
dstpic = XRenderCreatePicture(xw.dpy, xw.buf, fmt, 0, &pa);
|
XRenderFreePicture(xw.dpy, dstpic);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
XFreePixmap(xw.dpy, pm);
|
XRenderFreePicture(xw.dpy, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* scan the visible screen for placeholder glyphs and draw their images */
|
/* scan the visible screen for placeholder glyphs and draw their images */
|
||||||
|
|||||||
@ -61,6 +61,30 @@ 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)
|
||||||
@ -72,11 +96,19 @@ 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);
|
||||||
|
|
||||||
@ -143,6 +175,9 @@ 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;
|
||||||
@ -162,6 +197,11 @@ 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;
|
||||||
|
|
||||||
|
|||||||
@ -68,6 +68,9 @@ 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
|
||||||
|
|||||||
@ -357,6 +357,14 @@
|
|||||||
*/
|
*/
|
||||||
#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:
|
||||||
|
|||||||
@ -357,6 +357,14 @@
|
|||||||
*/
|
*/
|
||||||
#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:
|
||||||
|
|||||||
226
st.c
226
st.c
@ -143,6 +143,7 @@ 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];
|
||||||
@ -226,6 +227,7 @@ 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 );
|
||||||
@ -270,6 +272,115 @@ 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)
|
||||||
{
|
{
|
||||||
@ -1204,6 +1315,9 @@ 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
|
||||||
@ -1508,9 +1622,13 @@ 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';
|
||||||
@ -1610,6 +1728,10 @@ 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)
|
||||||
@ -1951,6 +2073,49 @@ 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
|
||||||
|
#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)
|
||||||
{
|
{
|
||||||
@ -2535,9 +2700,47 @@ csihandle(void)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif // CSI_22_23_PATCH | SIXEL_PATCH
|
#endif // CSI_22_23_PATCH | SIXEL_PATCH
|
||||||
case 'u': /* DECRC -- Restore cursor position (ANSI.SYS) */
|
case 'u':
|
||||||
|
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 */
|
||||||
@ -2678,8 +2881,29 @@ 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:
|
||||||
|
|||||||
11
st.h
11
st.h
@ -150,6 +150,9 @@ 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;
|
||||||
@ -208,6 +211,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_OSC8_PATCH
|
||||||
|
char *cwd; /* working directory reported via OSC 7, or NULL */
|
||||||
|
#endif // OSC7_OSC8_PATCH
|
||||||
} Term;
|
} Term;
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
@ -376,6 +382,11 @@ 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 *);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user