From 98687fa1dec803f041cbb5417c146d8aa5129b53 Mon Sep 17 00:00:00 2001 From: Oliver Kiddle Date: Fri, 19 Jun 2015 00:15:38 +0200 Subject: 35474, 35492: support the bracketed paste mode of newer terminal emulators --- Src/Zle/complist.c | 79 ++++++++++++++++++++++++++++----------------------- Src/Zle/iwidgets.list | 1 + Src/Zle/zle_hist.c | 15 ++++++++++ Src/Zle/zle_keymap.c | 5 ++++ Src/Zle/zle_main.c | 15 +++++++++- Src/Zle/zle_misc.c | 68 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 147 insertions(+), 36 deletions(-) (limited to 'Src/Zle') diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c index 39c0c314d..0f73181f3 100644 --- a/Src/Zle/complist.c +++ b/Src/Zle/complist.c @@ -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); diff --git a/Src/Zle/iwidgets.list b/Src/Zle/iwidgets.list index b41661a7d..6a07212d0 100644 --- a/Src/Zle/iwidgets.list +++ b/Src/Zle/iwidgets.list @@ -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 diff --git a/Src/Zle/zle_hist.c b/Src/Zle/zle_hist.c index 0b3b9e7b7..ffb7ce98f 100644 --- a/Src/Zle/zle_hist.c +++ b/Src/Zle/zle_hist.c @@ -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 { diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c index c6fae251d..d355f41a4 100644 --- a/Src/Zle/zle_keymap.c +++ b/Src/Zle/zle_keymap.c @@ -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; diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index cec44c0ed..7ccfb686a 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -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; } diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c index 4669ef2ad..c2fb2e7f4 100644 --- a/Src/Zle/zle_misc.c +++ b/Src/Zle/zle_misc.c @@ -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; -- cgit 1.4.1