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:
parent
0a0ba5e664
commit
98687fa1de
9 changed files with 181 additions and 36 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue