From 6a691a3487cc26900475291ced12400318176aeb Mon Sep 17 00:00:00 2001 From: Oliver Kiddle Date: Mon, 10 Nov 2025 21:02:31 +0100 Subject: 53404: terminal integration with semantic markers --- ChangeLog | 5 ++ Doc/Zsh/params.yo | 48 +++++++++---- Src/Zle/termquery.c | 170 +++++++++++++++++++++++++++++++++++++++++++++- Src/Zle/zle_main.c | 39 ++++++++--- Src/builtin.c | 7 +- Src/init.c | 9 ++- Src/input.c | 2 +- Src/loop.c | 2 +- Src/prompt.c | 9 ++- Src/subst.c | 4 +- Src/utils.c | 6 +- Src/zsh.h | 5 +- Test/X04zlehighlight.ztst | 4 +- Test/X06termquery.ztst | 17 +++-- 14 files changed, 281 insertions(+), 46 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8c652ad77..5371ac3e5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2025-11-10 Oliver Kiddle + * 53404: Doc/Zsh/params.yo, Src/Zle/termquery.c, Src/Zle/zle_main.c, + Src/builtin.c, Src/init.c, Src/input.c, Src/loop.c, Src/prompt.c, + Src/subst.c, Src/utils.c, Src/zsh.h, Test/X04zlehighlight.ztst, + Test/X06termquery.ztst: terminal integration with semantic markers + * 53379, 53380: Doc/Zsh/params.yo, Test/X04zlehighlight.ztst, Src/prompt.c: autoload nearcolor based on truecolor detection diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo index 7bcd61531..6cb9167d5 100644 --- a/Doc/Zsh/params.yo +++ b/Doc/Zsh/params.yo @@ -1741,6 +1741,30 @@ startup. Extensions can be any of the following, where the marks `' and `' indicate whether they are disabled or enabled by default: startitem() +item(tt(bracketed-paste) )( +Many terminal emulators have a feature that allows applications to identify +when text is pasted into the terminal rather than being typed normally. For +ZLE, this means that special characters such as tabs and newlines can be +inserted instead of invoking editor commands. Furthermore, pasted text forms a +single undo event and if the region is active, pasted text will replace the +region. +) +item(tt(integration-output) )( +This provides the terminal with semantic information regarding where the output +from commands start and finish. Some terminals use this information to make it +easy to select just the output from a single command. +) +item(tt(integration-prompt) )( +This informs the terminal when the shell displays a prompt. This enables a +variety of terminal features such as displaying markers, allowing you to jump +to previous commands in the scroll-back buffer and ensuring that right prompts +are handled correctly when the window is resized. The end of the prompt also +provides the terminal with a marker for the start of user input. +) +item(tt(integration-pwd) )( +This advises the terminal of the shell's current directory which allows it +to create new windows with the same current working directory. +) item(tt(query-bg) )( Query the terminal background color which is used for tt(.term.bg) and tt(.term.mode). @@ -1759,6 +1783,11 @@ wider range of key combinations and resolves problems with ambiguous key sequences. Currently there is only support for detecting whether the terminal supports this feature. ) +item(tt(modkeys-xterm) )( +Support for the keyboard handling sequences associated with xterm's +tt(modifyOtherKeys) X resource. This enables reporting of a wider range of key +combinations and resolves some problems with ambiguous key sequences. +) xitem(tt(truecolor) ) item(tt(query-truecolor) )( Support for 24-bit truecolor escape sequences. Auto-detection also tries @@ -1863,18 +1892,13 @@ vindex(zle_bracketed_paste) cindex(bracketed paste) cindex(enabling bracketed paste) item(tt(zle_bracketed_paste))( -Many terminal emulators have a feature that allows applications to -identify when text is pasted into the terminal rather than being typed -normally. For ZLE, this means that special characters such as tabs -and newlines can be inserted instead of invoking editor commands. -Furthermore, pasted text forms a single undo event and if the region is -active, pasted text will replace the region. - -This two-element array contains the terminal escape sequences for -enabling and disabling the feature. These escape sequences are used to -enable bracketed paste when ZLE is active and disable it at other times. -Unsetting the parameter has the effect of ensuring that bracketed paste -remains disabled. +This two-element array contains the terminal escape sequences for enabling and +disabling the bracketed paste feature which allows ZLE to discern text that is +pasted into the terminal. These escape sequences are used to enable bracketed +paste when ZLE is active and disable it at other times. Unsetting the +parameter has the effect of ensuring that bracketed paste remains disabled. +However, see also the tt(.term.extensions) parameter which provides a single +place to enable or disable terminal features. ) vindex(zle_highlight) item(tt(zle_highlight))( diff --git a/Src/Zle/termquery.c b/Src/Zle/termquery.c index 7305ba1d1..c9fd22588 100644 --- a/Src/Zle/termquery.c +++ b/Src/Zle/termquery.c @@ -223,8 +223,8 @@ probe_terminal(const char *tquery, seqstate_t *states, #endif settyinfo(&ti); - fputs(tquery, shout); - fflush(shout); + write_loop(SHTTY, tquery, strlen(tquery)); + notify_pwd(); /* unrelated to the function's main purpose */ while (!finish && *curstate) { int consumed = 0; /* whether an input token has been matched */ @@ -571,6 +571,28 @@ handle_paste(UNUSED(int sequence), UNUSED(int *numbers), UNUSED(int len), *(char**) output = base64_decode(capture, clen); } +static char* +url_encode(const char* path, size_t *ulen) +{ + char *url = zhalloc(strlen(path) * 3 + 1); /* worst case length triples */ + const char *in = path; + char *out = url; + + for (; *in; in++) { + /* In theory, space can be encoded as '+' but not all terminals + * handled that and %20 works reliably. + * ':' as a Windows drive letter should also not be encoded */ + if (isalnum(*in) || strchr("-._~/", *in)) + *out++ = *in; /* untouched in encoding */ + else + out += sprintf(out, "%%%02X", *in); /* otherwise %HH */ + } + + *out = '\0'; + *ulen = out - url; + return url; +} + /**/ char * system_clipget(char clip) @@ -588,5 +610,147 @@ void system_clipput(char clip, char *content, size_t clen) { char *encoded = base64_encode(content, clen); - fprintf(shout, "\033]52;%c;%s\a", clip, encoded); + fprintf(shout, "\033]52;%c;%s\033\\", clip, encoded); +} + +/**/ +static int +extension_enabled(const char *class, const char *ext, unsigned clen, int def) +{ + char **e, **elist = getaparam(EXTVAR); + + for (e = elist; e && *e; e++) { + int negate = (**e == '-'); + if (strncmp(*e + negate, class, clen)) + continue; + + if (!*(*e + negate + clen) || !strcmp(*e + negate + clen, ext)) + return !negate; + } + return def; +} + + +struct extension { + char *key, *seq[2]; + int class, enabled; +}; + +static const struct extension editext[] = { + { "bracketed-paste", { NULL, NULL}, 0, 1 }, + { "integration-prompt", { "\033]133;B\033\\" }, 11, 1 }, +#if 0 + { "modkeys-kitty", { "\033[=5u", "\033[=0u" }, 7, 0 }, +#endif + { "modkeys-xterm", { "\033[>4;1m", "\033[>4m" }, 7, 0 } +}; + +static void +collate_seq(int sindex, int dir) +{ + char seq[256]; + char *pos = seq; + int max = sizeof(editext) / sizeof(*editext); + int i; + char **bracket; + char **e, **elist = getaparam(EXTVAR); + + for (i = dir > 0 ? 0 : max - 1; i >= 0 && i < max; i += dir) { + int enabled = editext[i].enabled; + if (i && !editext[i].seq[sindex]) + continue; + for (e = elist; e && *e; e++) { + int negate = (**e == '-'); + if (negate != enabled) + continue; + if ((editext[i].class && + !strncmp(*e + negate, editext[i].key, editext[i].class) && + !*(*e + negate + editext[i].class)) || + !strcmp(*e + negate + editext[i].class, + editext[i].key + editext[i].class)) + { + enabled = !negate; + break; + } + + } + if (enabled) { + if (i) + strucpy(&pos, editext[i].seq[sindex]); + else if ((bracket = getaparam("zle_bracketed_paste")) && + arrlen(bracket) == 2) + strucpy(&pos, bracket[sindex]); + } + } + write_loop(SHTTY, seq, pos - seq); +} + +/**/ +void +start_edit(void) +{ + collate_seq(0, 1); +} + +/**/ +void +end_edit(void) +{ + collate_seq(1, -1); +} + +/**/ +const char ** +prompt_markers(void) +{ + static unsigned aid = 0; + static char pre[] = "\033]133;A;cl=m;aid=zZZZZZZ\033\\"; /* before the prompt */ + static const char *const PR = "\033]133;P;k=i\033\\"; /* primary (PS1) */ + static const char *const SE = "\033]133;P;k=s\033\\"; /* secondary (PS2) */ + static const char *const RI = "\033]133;P;k=r\033\\"; /* right (RPS1,2) */ + static const char *markers[] = { pre, PR, SE, RI }; + static const char *nomark[] = { NULL, NULL, NULL, NULL }; + + if (!extension_enabled("integration", "prompt", 11, 1)) + return nomark; + + if (!aid) { + /* hostname and pid should uniquely identify a shell instance */ + char *h = getsparam("HOST"); + aid = (h ? hasher(h) : 0) ^ getpid(); + if (!aid) aid = 1; /* unlikely but just to be safe */ + /* base64 not required but it is safe, convenient and compact */ + h = base64_encode((const char *)&aid, sizeof(aid)); + memcpy(pre + 13, h, 6); + } + + return markers; +} + +/**/ +void +mark_output(int start) +{ + static const char START[] = "\033]133;C\033\\"; + static const char END[] = "\033]133;D\033\\"; + if (extension_enabled("integration", "output", 11, 1)) + write_loop(SHTTY, start ? START : END, + (start ? sizeof(START) : sizeof(END)) - 1); +} + +/**/ +void +notify_pwd(void) +{ + char *url; + size_t ulen; + + if (!extension_enabled("integration", "pwd", 11, 1)) + return; + + url = url_encode(pwd, &ulen); + /* only "localhost" seems to be much use here as the host */ + write_loop(SHTTY, "\033]7;file://localhost", 20); + write_loop(SHTTY, url, ulen); + write_loop(SHTTY, "\033\\", 2); } diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 99ee3c804..6cea57112 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -1215,9 +1215,10 @@ zlecore(void) char * zleread(char **lp, char **rp, int flags, int context, char *init, char *finish) { - char *s, **bracket; + char *s; int old_errno = errno; int tmout = getiparam("TMOUT"); + const char **markers = prompt_markers(); #if defined(HAVE_POLL) || defined(HAVE_SELECT) /* may not be set, but that's OK since getiparam() returns 0 == off */ @@ -1232,7 +1233,7 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish) char *pptbuf; int pptlen; - pptbuf = unmetafy(promptexpand(lp ? *lp : NULL, 0, NULL, NULL), + pptbuf = unmetafy(promptexpand(lp ? *lp : NULL, 0, NULL, NULL, NULL), &pptlen); pmpt_attr = txtcurrentattrs; write_loop(2, pptbuf, pptlen); @@ -1270,10 +1271,11 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish) trashedzle = 0; raw_lp = lp; txtcurrentattrs = txtpendingattrs = txtunknownattrs = 0; - lpromptbuf = promptexpand(lp ? *lp : NULL, 1, NULL, NULL); + lpromptbuf = promptexpand(lp ? *lp : NULL, 1, + markers[flags == ZLCON_LINE_CONT ? 2 : 1], NULL, NULL); pmpt_attr = txtcurrentattrs; raw_rp = rp; - rpromptbuf = promptexpand(rp ? *rp : NULL, 1, NULL, NULL); + rpromptbuf = promptexpand(rp ? *rp : NULL, 1, markers[2], NULL, NULL); rpmpt_attr = txtcurrentattrs; prompt_attr = mixattrs(pmpt_attr, rpmpt_attr); free_prepostdisplay(); @@ -1344,6 +1346,10 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish) prefixflag = 0; region_active = 0; + /* semantic prompt marker printed before first prompt */ + if (*markers) + write_loop(2, *markers, strlen(*markers)); + zrefresh(); unqueue_signals(); /* Should now be safe to acknowledge SIGWINCH */ @@ -1353,8 +1359,7 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish) if (zleline && *zleline) redrawhook(); - if ((bracket = getaparam("zle_bracketed_paste")) && arrlen(bracket) == 2) - fputs(*bracket, shout); + start_edit(); zrefresh(); @@ -1365,8 +1370,7 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish) "ZLE_VARED_ABORTED" : "ZLE_LINE_ABORTED", zlegetline(NULL, NULL)); - if ((bracket = getaparam("zle_bracketed_paste")) && arrlen(bracket) == 2) - fputs(bracket[1], shout); + end_edit(); if (done && !exit_pending && !errflag) zlecallhook(finish, NULL); @@ -1895,11 +1899,13 @@ describekeybriefly(UNUSED(char **args)) return 1; clearlist = 1; statusline = "Describe key briefly: _"; + start_edit(); zrefresh(); if (invicmdmode() && region_active && (km = openkeymap("visual"))) selectlocalmap(km); seq = getkeymapcmd(curkeymap, &func, &str); selectlocalmap(NULL); + end_edit(); statusline = NULL; if(!*seq) return 1; @@ -1997,6 +2003,7 @@ reexpandprompt(void) static int looping; if (!reexpanding++) { + const char **markers = prompt_markers(); /* * If we're displaying a status in the prompt, it * needs to be the toplevel one, not the one from @@ -2015,7 +2022,7 @@ reexpandprompt(void) looping = reexpanding; txtcurrentattrs = txtpendingattrs = txtunknownattrs = 0; - new_lprompt = promptexpand(raw_lp ? *raw_lp : NULL, 1, NULL, NULL); + new_lprompt = promptexpand(raw_lp ? *raw_lp : NULL, 1, markers[0], NULL, NULL); pmpt_attr = txtcurrentattrs; free(lpromptbuf); lpromptbuf = new_lprompt; @@ -2023,7 +2030,7 @@ reexpandprompt(void) if (looping != reexpanding) continue; - new_rprompt = promptexpand(raw_rp ? *raw_rp : NULL, 1, NULL, NULL); + new_rprompt = promptexpand(raw_rp ? *raw_rp : NULL, 1, markers[2], NULL, NULL); rpmpt_attr = txtcurrentattrs; prompt_attr = mixattrs(pmpt_attr, rpmpt_attr); free(rpromptbuf); @@ -2177,6 +2184,18 @@ zle_main_entry(int cmd, va_list ap) break; } + case ZLE_CMD_PREEXEC: + mark_output(1); + break; + + case ZLE_CMD_POSTEXEC: + mark_output(0); + break; + + case ZLE_CMD_CHPWD: + notify_pwd(); + break; + default: #ifdef DEBUG dputs("Bad command %d in zle_main_entry", cmd); diff --git a/Src/builtin.c b/Src/builtin.c index 23067abe1..9ddaad93e 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -1258,8 +1258,11 @@ cd_new_pwd(int func, LinkNode dir, int quiet) /* execute the chpwd function */ fflush(stdout); fflush(stderr); - if (!quiet) + if (!quiet) { callhookfunc("chpwd", NULL, 1, NULL); + if (zle_load_state == 1) + zleentry(ZLE_CMD_CHPWD); + } dirstacksize = getiparam("DIRSTACKSIZE"); /* handle directory stack sizes out of range */ @@ -4798,7 +4801,7 @@ bin_print(char *name, char **args, Options ops, int func) */ char *str = unmetafy( promptexpand(metafy(args[n], len[n], META_NOALLOC), - 0, NULL, NULL), + 0, NULL, NULL, NULL), &len[n]); args[n] = dupstrpfx(str, len[n]); free(str); diff --git a/Src/init.c b/Src/init.c index dfef860f7..dea52202e 100644 --- a/Src/init.c +++ b/Src/init.c @@ -213,12 +213,17 @@ loop(int toplevel, int justonce) */ errflag &= ~ERRFLAG_ERROR; } + if (toplevel && zle_load_state == 1) + zleentry(ZLE_CMD_PREEXEC); if (stopmsg) /* unset 'you have stopped jobs' flag */ stopmsg--; execode(prog, 0, 0, toplevel ? "toplevel" : "file"); tok = toksav; - if (toplevel) + if (toplevel) { noexitct = 0; + if (zle_load_state == 1) + zleentry(ZLE_CMD_POSTEXEC); + } } if (ferror(stderr)) { zerr("write error"); @@ -1803,7 +1808,7 @@ VA_DCL lp = va_arg(ap, char **); - pptbuf = unmetafy(promptexpand(lp ? *lp : NULL, 0, NULL, NULL), + pptbuf = unmetafy(promptexpand(lp ? *lp : NULL, 0, NULL, NULL, NULL), &pptlen); write_loop(2, pptbuf, pptlen); free(pptbuf); diff --git a/Src/input.c b/Src/input.c index b78c91680..9b8e57f6a 100644 --- a/Src/input.c +++ b/Src/input.c @@ -399,7 +399,7 @@ inputline(void) char *pptbuf; int pptlen; pptbuf = unmetafy(promptexpand(ingetcpmptl ? *ingetcpmptl : NULL, - 0, NULL, NULL), &pptlen); + 0, NULL, NULL, NULL), &pptlen); write_loop(2, pptbuf, pptlen); free(pptbuf); } diff --git a/Src/loop.c b/Src/loop.c index ba01b1da5..db78f00c7 100644 --- a/Src/loop.c +++ b/Src/loop.c @@ -282,7 +282,7 @@ execselect(Estate state, UNUSED(int do_exec)) /* Keep any user interrupt error status */ errflag = oef | (errflag & ERRFLAG_INT); } else { - str = promptexpand(prompt3, 0, NULL, NULL); + str = promptexpand(prompt3, 0, NULL, NULL, NULL); zputs(str, stderr); free(str); fflush(stderr); diff --git a/Src/prompt.c b/Src/prompt.c index 762d25650..25392b4c2 100644 --- a/Src/prompt.c +++ b/Src/prompt.c @@ -174,7 +174,7 @@ promptpath(char *p, int npath, int tilde) /**/ mod_export char * -promptexpand(char *s, int ns, char *rs, char *Rs) +promptexpand(char *s, int ns, const char *marker, char *rs, char *Rs) { struct buf_vars new_vars; @@ -218,6 +218,11 @@ promptexpand(char *s, int ns, char *rs, char *Rs) new_vars.bp1 = NULL; new_vars.truncwidth = 0; + if (marker && *s) { + *new_vars.bp++ = Inpar; + strucpy(&new_vars.bp, (char *) marker); + *new_vars.bp++ = Outpar; + } putpromptchar(1, '\0'); addbufspc(2); if (new_vars.dontcount) @@ -321,7 +326,7 @@ parsecolorchar(zattr arg, int is_fg) *ep = '\0'; /* expand the contents of the argument so you can use * %v for example */ - coll = col = promptexpand(bv->fm, 0, NULL, NULL); + coll = col = promptexpand(bv->fm, 0, NULL, NULL, NULL); *ep = oc; arg = match_colour((const char **)&coll, is_fg, 0); free(col); diff --git a/Src/subst.c b/Src/subst.c index be2333ca5..8d730163e 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -4001,7 +4001,7 @@ colonsubscript: char *tmps; untokenize(*ap); txtunknownattrs = TXT_ATTR_ALL; - tmps = promptexpand(*ap, 0, NULL, NULL); + tmps = promptexpand(*ap, 0, NULL, NULL, NULL); *ap = dupstring(tmps); free(tmps); } @@ -4011,7 +4011,7 @@ colonsubscript: val = dupstring(val), copied = 1; untokenize(val); txtunknownattrs = TXT_ATTR_ALL; - tmps = promptexpand(val, 0, NULL, NULL); + tmps = promptexpand(val, 0, NULL, NULL, NULL); val = dupstring(tmps); free(tmps); } diff --git a/Src/utils.c b/Src/utils.c index e7e3f4f8d..a1d7c8cc2 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -1556,7 +1556,7 @@ preprompt(void) eolmark = "%B%S%#%s%b"; opts[PROMPTPERCENT] = 1; txtunknownattrs = TXT_ATTR_ALL; - str = promptexpand(eolmark, 1, NULL, NULL); + str = promptexpand(eolmark, 1, NULL, NULL, NULL); countprompt(str, &w, 0, -1); opts[PROMPTPERCENT] = percents; zputs(str, shout); @@ -1726,7 +1726,7 @@ printprompt4(void) opts[XTRACE] = 0; unmetafy(s, &l); s = unmetafy(promptexpand(metafy(s, l, META_NOALLOC), - 0, NULL, NULL), &l); + 0, NULL, NULL, NULL), &l); opts[XTRACE] = t; fprintf(xtrerr, "%s", s); @@ -3275,7 +3275,7 @@ spckword(char **s, int hist, int cmd, int ask) x = 'n'; } else if (shout) { char *pptbuf; - pptbuf = promptexpand(sprompt, 0, best, guess); + pptbuf = promptexpand(sprompt, 0, NULL, best, guess); zputs(pptbuf, shout); free(pptbuf); fflush(shout); diff --git a/Src/zsh.h b/Src/zsh.h index 993108a8c..4d791cc7c 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -3235,7 +3235,10 @@ enum { ZLE_CMD_REFRESH, ZLE_CMD_SET_KEYMAP, ZLE_CMD_GET_KEY, - ZLE_CMD_SET_HIST_LINE + ZLE_CMD_SET_HIST_LINE, + ZLE_CMD_PREEXEC, + ZLE_CMD_POSTEXEC, + ZLE_CMD_CHPWD }; /***************************************/ diff --git a/Test/X04zlehighlight.ztst b/Test/X04zlehighlight.ztst index be0564912..ecb309605 100644 --- a/Test/X04zlehighlight.ztst +++ b/Test/X04zlehighlight.ztst @@ -12,7 +12,7 @@ zpty zsh "${(q)ZTST_testdir}/../Src/zsh -fiV +Z" zpty -w zsh "module_path=( ${(j< >)${(@q-)module_path}} \$module_path )" zpty -w zsh 'zle_highlight=( fg_start_code:"CDE|3" fg_end_code:"|" bg_start_code:"BCDE|4" bg_end_code:"|" )' - zpty -w zsh '.term.extensions=( -query truecolor )' + zpty -w zsh '.term.extensions=( -query truecolor -bracketed-paste -integration )' } zpty_input() { zpty ${${(M)2:#nonl}:+-n} -w zsh "$1" @@ -20,7 +20,7 @@ zpty_enable_zle() { zpty -w zsh "tcfunc() { REPLY=""; }" # This line will not be echoed back, behaving like ! -o zle - zpty -w zsh "setopt zle; zle -T tc tcfunc; unset zle_bracketed_paste" + zpty -w zsh "setopt zle; zle -T tc tcfunc" } zpty_line() { setopt localoptions extendedglob noshwordsplit diff --git a/Test/X06termquery.ztst b/Test/X06termquery.ztst index cce4e626f..5f3a81aae 100644 --- a/Test/X06termquery.ztst +++ b/Test/X06termquery.ztst @@ -9,6 +9,7 @@ zpty -d zpty zsh "${(q)ZTST_testdir}/../Src/zsh -fiV +Z" zpty -w zsh "module_path=( ${(j< >)${(@q-)module_path}} \$module_path )" + zpty -w zsh ".term.extensions=( -bracketed-paste -integration )" zpty -w zsh "setopt zle" zpty -r zsh REPLY $'\e*\r' zpty -n -w zsh "$1" @@ -30,7 +31,7 @@ >typeset .term.bg='#ffffdd' >typeset .term.version=1.20.2 >typeset .term.mode=light ->typeset -a .term.extensions=( modkeys-kitty truecolor ) +>typeset -a .term.extensions=( -bracketed-paste -integration modkeys-kitty truecolor ) termresp $'\e]11;rgb:0/0/0\e\\\e]10;rgb:ff/ff/ff\e\\\eP>|Wayst(0.0.0)\e\\\e[?63;1;4c' 0:wayst response to terminal queries (shorter colour sequences) @@ -39,6 +40,7 @@ >typeset .term.bg='#000000' >typeset .term.version=0.0.0 >typeset .term.mode=dark +>typeset -a .term.extensions=( -bracketed-paste -integration ) termresp $'\e]11;rgb:0000/0000/0000\e\\\e]10;rgb:b2b2/b2b2/b2b2\e\\\eP1+r524742=382F382F38\e\\\eP>|WezTerm 20240203-110809-5046fc22\e\\\e[?65;4;6;18;22c' 0:WezTerm response to terminal queries (space separates version and longer RGB response) @@ -47,13 +49,14 @@ >typeset .term.bg='#000000' >typeset .term.version=20240203-110809-5046fc22 >typeset .term.mode=dark ->typeset -a .term.extensions=( truecolor ) +>typeset -a .term.extensions=( -bracketed-paste -integration truecolor ) termresp $'\e]11;rgb:9600/8700/7900\e\e]10;rgb:0000/0000/0000\e\e[?1;2c' 0:urxvt response to terminal queries (bug in end of colour sequences) >typeset .term.fg='#000000' >typeset .term.bg='#968779' >typeset .term.mode=light +>typeset -a .term.extensions=( -bracketed-paste -integration ) termresp $'\e]11;rgb:0000/0000/0000\e\\\e]10;rgb:dddd/dddd/dddd\e\\\e[?0u\eP0+r524742\e\\\eP>|kitty(0.36.4)\e\\\e[?62;c' 0:kitty response to terminal queries (responds with error to RGB request) @@ -62,7 +65,7 @@ >typeset .term.bg='#000000' >typeset .term.version=0.36.4 >typeset .term.mode=dark ->typeset -a .term.extensions=( modkeys-kitty ) +>typeset -a .term.extensions=( -bracketed-paste -integration modkeys-kitty ) termresp $'\e]11;rgb:0000/ffff/8c8c\e\\\e]10;rgb:0000/0000/0000\e\\\eP1+r524742=38\e\\\eP>|XTerm(396)\e\\\e[?64;1;2;6;9;15;16;17;18;21;22;28c' 0:xterm response to terminal queries @@ -71,7 +74,7 @@ >typeset .term.bg='#00ff8c' >typeset .term.version=396 >typeset .term.mode=light ->typeset -a .term.extensions=( truecolor ) +>typeset -a .term.extensions=( -bracketed-paste -integration truecolor ) termresp $'echo type\e]11;rgb:0/0/0\aah\e]10;rgb:A/B/C\aea\e[?0u\eP0+r\e\\d\n\e[?0;c' 0:type-ahead @@ -79,24 +82,28 @@ >typeset .term.fg='#0a0b0c' >typeset .term.bg='#000000' >typeset .term.mode=dark ->typeset -a .term.extensions=( modkeys-kitty ) +>typeset -a .term.extensions=( -bracketed-paste -integration modkeys-kitty ) termresp '' 0:no response - timeout +>typeset -a .term.extensions=( -bracketed-paste -integration ) # Following three vi-put tests also cover 0, 1 and 2 `=' padding # characters in the base64 decoding. termresp $'\e[?0;cbindkey -v\necho \e"*p\e]52;p;YWZ0ZXI=\aa\n' 0:paste after from clipboard >after +>typeset -a .term.extensions=( -bracketed-paste -integration ) termresp $'\e[?0;cbindkey -v\necho X\e"*P\e]52;p;YmVmb3Jl\aa\n' 0:paste before from clipboard >beforeX +>typeset -a .term.extensions=( -bracketed-paste -integration ) termresp $'\e[?0;cbindkey -v\necho X\ev"*p\e]52;p;cmVwbGFjZQ==\aa\n' 0:paste over from clipboard >replace +>typeset -a .term.extensions=( -bracketed-paste -integration ) %clean -- cgit v1.2.3-70-g09d2