1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2024-12-28 16:15:02 +01:00

35474, 35492: support the bracketed paste mode of newer terminal emulators

This commit is contained in:
Oliver Kiddle 2015-06-19 00:15:38 +02:00
parent 0a0ba5e664
commit 98687fa1de
9 changed files with 181 additions and 36 deletions

View file

@ -1,5 +1,10 @@
2015-06-18 Oliver Kiddle <opk@zsh.org>
* 35474, 35492: Doc/Zsh/params.yo, Doc/Zsh/zle.yo,
Src/Zle/complist.c, Src/Zle/iwidgets.list, Src/Zle/zle_hist.c,
Src/Zle/zle_keymap.c, Src/Zle/zle_main.c: support the
bracketed paste mode of newer terminal emulators
* 35487, 35496: Doc/Zsh/zle.yo, Src/Zle/complist.c,
Src/Zle/zle_hist.c: don't reinstate previous incremental search
string when search direction changes

View file

@ -1642,6 +1642,23 @@ item(tt(ZDOTDIR))(
The directory to search for shell startup files (.zshrc, etc),
if not tt($HOME).
)
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.
)
vindex(ZLE_LINE_ABORTED)
item(tt(ZLE_LINE_ABORTED))(
This parameter is set by the line editor when an error occurs. It

View file

@ -2059,6 +2059,18 @@ tindex(beep)
item(tt(beep))(
Beep, unless the tt(BEEP) option is unset.
)
tindex(bracketed-paste)
item(tt(bracketed-paste))(
This widget is invoked when text is pasted to the terminal emulator. It
is not intended to be bound to actual keys but instead to the special
sequence generated by the terminal emulator when text is pasted.
If a numeric argument is given, shell quoting will be applied to the
pasted text before it is inserted. When called from a widget function,
an argument can be given to specify a variable to which pasted text is
assigned.
See also the tt(zle_bracketed_paste) parameter.
)
tindex(vi-cmd-mode)
item(tt(vi-cmd-mode) (tt(^X^V)) (unbound) (tt(^[)))(
Enter command mode; that is, select the `tt(vicmd)' keymap.

View file

@ -2269,41 +2269,16 @@ msearchpop(int *backp)
}
static Cmatch **
msearch(Cmatch **ptr, int ins, int back, int rep, int *wrapp)
msearch(Cmatch **ptr, char *ins, int back, int rep, int *wrapp)
{
#ifdef MULTIBYTE_SUPPORT
/* MB_CUR_MAX may not be constant */
VARARR(char, s, MB_CUR_MAX+1);
#else
char s[2];
#endif
Cmatch **p, *l = NULL, m;
int x = mcol, y = mline;
int ex, ey, wrap = 0, owrap = (msearchstate & MS_WRAPPED);
msearchpush(ptr, back);
if (ins) {
#ifdef MULTIBYTE_SUPPORT
if (lastchar_wide_valid)
{
mbstate_t mbs;
int len;
memset(&mbs, 0, sizeof(mbs));
len = wcrtomb(s, lastchar_wide, &mbs);
if (len < 0)
len = 0;
s[len] = '\0';
} else
#endif
{
s[0] = lastchar;
s[1] = '\0';
}
msearchstr = dyncat(msearchstr, s);
}
if (ins)
msearchstr = dyncat(msearchstr, ins);
if (back) {
ex = mcols - 1;
ey = -1;
@ -3273,14 +3248,23 @@ domenuselect(Hookdef dummy, Chdata dat)
cmd == Th(z_historyincrementalsearchbackward) ||
((mode == MM_FSEARCH || mode == MM_BSEARCH) &&
(cmd == Th(z_selfinsert) ||
cmd == Th(z_selfinsertunmeta)))) {
cmd == Th(z_selfinsertunmeta) ||
cmd == Th(z_bracketedpaste)))) {
Cmatch **np, **op = p;
int was = (mode == MM_FSEARCH || mode == MM_BSEARCH);
int ins = (cmd == Th(z_selfinsert) || cmd == Th(z_selfinsertunmeta));
int ins = (cmd == Th(z_selfinsert) || cmd == Th(z_selfinsertunmeta) ||
cmd == Th(z_bracketedpaste));
int back = (cmd == Th(z_historyincrementalsearchbackward));
int wrap;
do {
char *toins = NULL;
#ifdef MULTIBYTE_SUPPORT
/* MB_CUR_MAX may not be constant */
VARARR(char, insert, MB_CUR_MAX+1);
#else
char insert[2];
#endif
if (was) {
p += wishcol - mcol;
mcol = wishcol;
@ -3297,16 +3281,41 @@ domenuselect(Hookdef dummy, Chdata dat)
msearchstack = NULL;
msearchstate = MS_OK;
}
}
if (cmd == Th(z_selfinsertunmeta)) {
fixunmeta();
}
} else {
if (cmd == Th(z_selfinsertunmeta)) {
fixunmeta();
}
if (cmd == Th(z_bracketedpaste)) {
toins = bracketedstring();
} else {
toins = insert;
#ifdef MULTIBYTE_SUPPORT
if (lastchar_wide_valid)
{
mbstate_t mbs;
int len;
memset(&mbs, 0, sizeof(mbs));
len = wcrtomb(s, lastchar_wide, &mbs);
if (len < 0)
len = 0;
insert[len] = '\0';
} else
#endif
{
insert[0] = lastchar;
insert[1] = '\0';
}
}
}
wrap = 0;
np = msearch(p, ins, (ins ? (mode == MM_BSEARCH) : back),
np = msearch(p, toins, (ins ? (mode == MM_BSEARCH) : back),
(was && !ins), &wrap);
if (!ins)
mode = (back ? MM_BSEARCH : MM_FSEARCH);
else if (cmd == Th(z_bracketedpaste))
free(toins);
if (*msearchstr) {
zsfree(lastsearch);

View file

@ -28,6 +28,7 @@
"beginning-of-history", beginningofhistory, 0
"beginning-of-line", beginningofline, 0
"beginning-of-line-hist", beginningoflinehist, 0
"bracketed-paste", bracketedpaste, ZLE_MENUCMP | ZLE_KEEPSUFFIX
"capitalize-word", capitalizeword, 0
"clear-screen", clearscreen, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_NOTCOMMAND
"complete-word", completeword, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP

View file

@ -1620,6 +1620,21 @@ doisearch(char **args, int dir, int pattern)
feep = 1;
else
goto ins;
} else if (cmd == Th(z_bracketedpaste)) {
char *paste = bracketedstring();
set_isrch_spot(top_spot++, hl, pos, pat_hl, pat_pos, end_pos,
zlemetacs, sbptr, dir, nomatch);
size_t pastelen = strlen(paste);
if (sbptr + pastelen >= sibuf - FIRST_SEARCH_CHAR - 2) {
int oldsize = sibuf;
sibuf += (pastelen >= sibuf) ? pastelen + 1 : sibuf;
ibuf = hrealloc(ibuf, oldsize, sibuf);
sbuf = ibuf + FIRST_SEARCH_CHAR;
}
strcpy(sbuf + sbptr, paste);
sbptr += pastelen;
patprog = NULL;
free(paste);
} else if (cmd == Th(z_acceptsearch)) {
break;
} else {

View file

@ -1400,6 +1400,11 @@ default_bindings(void)
bindkey(emap, "\30\30", refthingy(t_exchangepointandmark), NULL);
bindkey(emap, "\30=", refthingy(t_whatcursorposition), NULL);
/* bracketed paste applicable to all keymaps */
bindkey(emap, "\33[200~", refthingy(t_bracketedpaste), NULL);
bindkey(vmap, "\33[200~", refthingy(t_bracketedpaste), NULL);
bindkey(amap, "\33[200~", refthingy(t_bracketedpaste), NULL);
/* emacs mode: ESC sequences, all taken from the meta binding table */
buf[0] = '\33';
buf[2] = 0;

View file

@ -1119,7 +1119,7 @@ zlecore(void)
char *
zleread(char **lp, char **rp, int flags, int context, char *init, char *finish)
{
char *s;
char *s, **bracket;
int old_errno = errno;
int tmout = getiparam("TMOUT");
@ -1248,6 +1248,9 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish)
zlecallhook(init, NULL);
if ((bracket = getaparam("zle_bracketed_paste")) && arrlen(bracket) == 2)
fputs(*bracket, shout);
zrefresh();
zlecore();
@ -1257,6 +1260,9 @@ 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);
if (done && !exit_pending && !errflag)
zlecallhook(finish, NULL);
@ -2004,6 +2010,8 @@ static struct features module_features = {
int
setup_(UNUSED(Module m))
{
char **bpaste;
/* Set up editor entry points */
zle_entry_ptr = zle_main_entry;
zle_load_state = 1;
@ -2028,6 +2036,11 @@ setup_(UNUSED(Module m))
clwords = (char **) zshcalloc((clwsize = 16) * sizeof(char *));
bpaste = zshcalloc(3*sizeof(char *));
bpaste[0] = ztrdup("\033[?2004h");
bpaste[1] = ztrdup("\033[?2004l");
setaparam("zle_bracketed_paste", bpaste);
return 0;
}

View file

@ -735,6 +735,58 @@ yankpop(UNUSED(char **args))
return 0;
}
/**/
char *
bracketedstring()
{
static const char endesc[] = "\033[201~";
int endpos = 0;
size_t psize = 64;
char *pbuf = zalloc(psize);
size_t current = 0;
int next, timeout;
while (endesc[endpos]) {
if (current + 1 >= psize)
pbuf = zrealloc(pbuf, psize *= 2);
if ((next = getbyte(1L, &timeout)) == EOF)
break;
if (!endpos || next != endesc[endpos++])
endpos = (next == *endesc);
if (imeta(next)) {
pbuf[current++] = Meta;
pbuf[current++] = next ^ 32;
} else if (next == '\r')
pbuf[current++] = '\n';
else
pbuf[current++] = next;
}
pbuf[current-endpos] = '\0';
return pbuf;
}
/**/
int
bracketedpaste(char **args)
{
char *pbuf = bracketedstring();
if (*args) {
setsparam(*args, pbuf);
} else {
int n;
ZLE_STRING_T wpaste;
wpaste = stringaszleline((zmult == 1) ? pbuf :
quotestring(pbuf, NULL, QT_BACKSLASH), 0, &n, NULL, NULL);
zmult = 1;
if (region_active)
killregion(zlenoargs);
doinsert(wpaste, n);
free(pbuf); free(wpaste);
}
return 0;
}
/**/
int
overwritemode(UNUSED(char **args))
@ -1264,6 +1316,22 @@ executenamedcommand(char *prmt)
if (listed)
clearlist = listshown = 1;
curlist = 0;
} else if (cmd == Th(z_bracketedpaste)) {
char *insert = bracketedstring();
size_t inslen = strlen(insert);
if (len + inslen > NAMLEN)
feep = 1;
else {
strcpy(ptr, insert);
len += inslen;
ptr += inslen;
if (listed) {
clearlist = listshown = 1;
listed = 0;
} else
curlist = 0;
}
free(insert);
} else {
if(cmd == Th(z_acceptline) || cmd == Th(z_vicmdmode)) {
Thingy r;