diff --git a/.st.h.swn b/.st.h.swn new file mode 100644 index 0000000..7f009ac Binary files /dev/null and b/.st.h.swn differ diff --git a/.st.h.swo b/.st.h.swo new file mode 100644 index 0000000..e8acfc8 Binary files /dev/null and b/.st.h.swo differ diff --git a/.st.h.swp b/.st.h.swp new file mode 100644 index 0000000..e6ecb3f Binary files /dev/null and b/.st.h.swp differ diff --git a/config.def.h b/config.def.h index ca145fc..d733228 100644 --- a/config.def.h +++ b/config.def.h @@ -90,6 +90,10 @@ int allowaltscreen = 1; setting the clipboard text */ 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. * within this range, st draws when content stops arriving (idle). mostly it's diff --git a/config.h b/config.h index 56659b4..d08b50b 100644 --- a/config.h +++ b/config.h @@ -90,6 +90,10 @@ int allowaltscreen = 1; setting the clipboard text */ 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. * within this range, st draws when content stops arriving (idle). mostly it's diff --git a/st.c b/st.c index 9e1c061..b74c90d 100644 --- a/st.c +++ b/st.c @@ -117,6 +117,7 @@ enum escape_state { #if SIXEL_PATCH ESC_DCS =128, #endif // SIXEL_PATCH + ESC_DCS_IGNORE =256, /* discarding an unknown DCS until ST */ }; typedef struct { @@ -2100,6 +2101,7 @@ tmodestatus(int priv, int mode) #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; @@ -2174,6 +2176,8 @@ tsetmode(int priv, int set, const int *args, int narg) case 1004: /* 1004: send focus events to tty */ xsetmode(set, MODE_FOCUS); break; + case 7727: /* 7727: extended keys (tmux/mintty), not supported */ + break; case 1006: /* 1006: extended reporting mode */ xsetmode(set, MODE_MOUSESGR); break; @@ -2328,6 +2332,22 @@ csihandle(void) } break; 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) ttywrite(vtiden, strlen(vtiden), 0); break; @@ -2634,6 +2654,18 @@ csihandle(void) term.c.y+1, term.c.x+1); ttywrite(buffer, len, 0); 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: goto unknown; } @@ -2871,7 +2903,7 @@ strhandle(void) #endif // CSI_22_23_PATCH return; case 52: - if (narg > 2 && allowwindowops) { + if (narg > 2 && (allowwindowops || allowclipboard)) { dec = base64dec(strescseq.args[2]); if (dec) { xsetsel(dec); @@ -3369,9 +3401,13 @@ dcshandle(void) switch (csiescseq.mode[0]) { default: unknown: - fprintf(stderr, "erresc: unknown csi "); - csidump(); - /* die(""); */ + /* + * An unknown DCS, e.g. the "DCS tmux;" passthrough wrapper or + * XTGETTCAP. Its body must not be interpreted, so discard every + * 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; #if SYNC_PATCH case '=': @@ -3541,6 +3577,23 @@ tputc(Rune u) * receives a ESC, a SUB, a ST or any other C1 control * character. */ + if (term.esc & ESC_DCS_IGNORE) { + static int sawesc; + if (sawesc) { + sawesc = 0; + if (u == '\\') { + term.esc = 0; + return; + } + /* ESC ESC or ESC : still inside the payload */ + if (u != 033) + return; + } + if (u == 033) + sawesc = 1; + return; + } + if (term.esc & ESC_STR) { if (u == '\a' || u == 030 || u == 032 || u == 033 || ISCONTROLC1(u)) { diff --git a/st.h b/st.h index 437498b..0408f4d 100644 --- a/st.h +++ b/st.h @@ -415,6 +415,7 @@ extern wchar_t *kbds_ldelim; #endif // KEYBOARDSELECT_PATCH extern int allowaltscreen; extern int allowwindowops; +extern int allowclipboard; extern char *termname; extern unsigned int tabspaces; extern unsigned int defaultfg; diff --git a/st.info b/st.info index b286fb5..5935bba 100644 --- a/st.info +++ b/st.info @@ -199,11 +199,20 @@ st-mono| simpleterm monocolor, # rep=%p1%c\E[%p2%{1}%-%db, # tmux extensions, see TERMINFO EXTENSIONS in tmux(1) Tc, + RGB, Ms=\E]52;%p1%s;%p2%s\007, Se=\E[2 q, Ss=\E[%p1%d q, # sync patch / SYNC_PATCH 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, use=st-mono,