53404: terminal integration with semantic markers

This commit is contained in:
Oliver Kiddle
2025-11-10 21:02:31 +01:00
committed by Oliver Kiddle
parent 3085b88a64
commit 6a691a3487
14 changed files with 281 additions and 46 deletions

View File

@@ -1,5 +1,10 @@
2025-11-10 Oliver Kiddle <opk@zsh.org>
* 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

View File

@@ -1741,6 +1741,30 @@ startup. Extensions can be any of the following, where the marks `<D>' and
`<E>' indicate whether they are disabled or enabled by default:
startitem()
item(tt(bracketed-paste) <E>)(
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) <E>)(
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) <E>)(
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) <E>)(
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) <E>)(
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) <D>)(
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) <D>)
item(tt(query-truecolor) <E>)(
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))(

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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
};
/***************************************/

View File

@@ -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

View File

@@ -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