* Re: bracketed paste mode in xterm and urxvt [not found] ` <CAHYJk3T3dVdN5qDMecPAH_ALLBYNntW0QVdPMh50Lo_ULeWP6w__21110.9288772152$1433333265$gmane$org@mail.gmail.com> @ 2015-06-03 12:43 ` Stephane Chazelas 0 siblings, 0 replies; 18+ messages in thread From: Stephane Chazelas @ 2015-06-03 12:43 UTC (permalink / raw) To: zsh-workers 2015-06-03 14:06:05 +0200, Mikael Magnusson: [...] > It's probably worth noting that 'safe-paste' is a bad name for this, > since the pasted text can include the end-paste escape code, causing > the rest of the paste to appear to the shell as typed by the user. > > This page has an example attack against the plugin, > https://thejh.net/misc/website-terminal-copy-paste > > Hm, seems newer xterm prohibits pasting raw escape codes, so if you > have one of those versions, you are safe. [...] Yes, see: https://security.stackexchange.com/questions/39118/how-can-i-protect-myself-from-this-kind-of-clipboard-abuse/52655#52655 for details. Note that with xterm, it's also possible to configure it to do another safe type of bracketed paste like: xterm -xrm 'XTerm.VT100.translations: #override Shift <KeyPress> space: insert-formatted("\033[202~%S~%s", CLIPBOARD)' For the CLIPBOARD selection to be inserted as ^[[202~3~abc (here upon Shift+Space). That is with the content of the selection prefixed with its length (in bytes) -- Stephane ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: bracketed paste mode in xterm and urxvt [not found] ` <mk9dc0$p0$1@ger.gmane.org> [not found] ` <CABZhJg_5p8BLbq82s_wVtsPdD5hVtk-cPg6fNxzbSs4Vg00SOw@mail.gmail.com> @ 2015-06-03 15:31 ` Oliver Kiddle 2015-06-03 20:42 ` Stephane Chazelas 2015-06-05 10:49 ` Yuri D'Elia 1 sibling, 2 replies; 18+ messages in thread From: Oliver Kiddle @ 2015-06-03 15:31 UTC (permalink / raw) To: zsh-workers [ moved to -workers ] Yuri D'Elia wrote: > On 05/28/2015 10:30 PM, Daniel Hahler wrote: > > Apart from that I think that this (bracketed paste mode) should be > > included in Zsh's and get maintained this way. Then it could also be > > adjusted for vi-mode. > > I do agree that mainlining this would make a lot of sense, even as a > setopt. Or at least provide the keymap/functions needed to enable it. I've been using bracketed paste for a while now and would also agree. The question is in what form to provide it? Note that I posted an alternative mechanism in workers/29898. The patch below is a port of that to C. This doesn't use a keymap which I don't think is any loss as such? Quoting is enabled with a numeric argument. I like the idea of using a Ctrl-X prefix to enable quoting but a small wrapper function can provide for that. With the patch as it stands, which is not meant to be final, users must still manually enable the mode for their terminal with zle-line-init etc (I actually append the strings to PS1/PS2/POSTEDIT). It'd certainly possible to add a setopt option to zsh to automatically output the enable/disable strings for bracketed paste. Testing a few ancient terminals (xterm and dtterm on Solaris 10), they seem to have no ill effect. Perhaps it'd be better to apply some sort of heuristics based on terminfo, however. Any thoughts on this? What behaviour would you want in vi-mode? What about with the region active? Replacing the region might make sense but isn't really what emacs or vim do. Oliver diff --git a/Src/Zle/iwidgets.list b/Src/Zle/iwidgets.list index b41661a..6a07212 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_keymap.c b/Src/Zle/zle_keymap.c index c6fae25..6da31f3 100644 --- a/Src/Zle/zle_keymap.c +++ b/Src/Zle/zle_keymap.c @@ -1400,6 +1400,10 @@ 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); + /* emacs mode: ESC sequences, all taken from the meta binding table */ buf[0] = '\33'; buf[2] = 0; diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c index 4669ef2..2eec8fa 100644 --- a/Src/Zle/zle_misc.c +++ b/Src/Zle/zle_misc.c @@ -737,6 +737,42 @@ yankpop(UNUSED(char **args)) /**/ int +bracketedpaste(UNUSED(char **args)) +{ + static const char endesc[] = "\e[201~"; + int endpos = 0; + size_t psize = 64; + char *buf, *pbuf = zalloc(psize); + size_t current = 0; + int n, next, timeout; + ZLE_STRING_T wpaste; + + while (endesc[endpos]) { + if ((next = getbyte(1L, &timeout)) == EOF) + break; + if (!endpos || next != endesc[endpos++]) + endpos = (next == *endesc); + if (current + 1 >= psize) + pbuf = zrealloc(pbuf, psize *= 2); + if (imeta(next)) { + pbuf[current++] = Meta; + pbuf[current++] = next ^ 32; + } else if (next == '\r') + pbuf[current++] = '\n'; + else + pbuf[current++] = next; + } + pbuf[current-sizeof(endesc)+1] = '\0'; + buf = zmult == 1 ? pbuf : quotestring(pbuf, NULL, QT_BACKSLASH); + zmult = 1; + wpaste = stringaszleline(buf, 0, &n, NULL, NULL); + doinsert(wpaste, n); + free(pbuf); free(wpaste); + return 0; +} + +/**/ +int overwritemode(UNUSED(char **args)) { insmode ^= 1; ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: bracketed paste mode in xterm and urxvt 2015-06-03 15:31 ` Oliver Kiddle @ 2015-06-03 20:42 ` Stephane Chazelas 2015-06-03 23:48 ` Oliver Kiddle 2015-06-05 10:49 ` Yuri D'Elia 1 sibling, 1 reply; 18+ messages in thread From: Stephane Chazelas @ 2015-06-03 20:42 UTC (permalink / raw) To: zsh-workers 2015-06-03 17:31:31 +0200, Oliver Kiddle: > [ moved to -workers ] > > Yuri D'Elia wrote: > > On 05/28/2015 10:30 PM, Daniel Hahler wrote: > > > Apart from that I think that this (bracketed paste mode) should be > > > included in Zsh's and get maintained this way. Then it could also be > > > adjusted for vi-mode. > > > > I do agree that mainlining this would make a lot of sense, even as a > > setopt. Or at least provide the keymap/functions needed to enable it. > > I've been using bracketed paste for a while now and would also agree. > The question is in what form to provide it? Note that I posted an > alternative mechanism in workers/29898. The patch below is a port of > that to C. [...] Also note that where terminals don't filter out control characters, there's a potential problem in the way ^C is handled. zsh disables all signal keys but "intr". If the data to paste (which is written in one go to the master side of the pty by the terminal emulator) contains ^C, then a SIGINT will be sent to zsh and the data from the start of the paste up to ^C will not be available for reading (discarded by the line discipline, at least on Linux). So any bracketed paste solution cannot be safe unless either ^C is removed by the terminal emulator (like newer versions of xterm), or ISIG is disabled in the terminal line-discipline. So, for a truly safe paste, zsh should probably do the equivalent of a stty -isig. That can only be done *before* the paste, so that means isig must be turned off all the time (at least when bracketed paste is enabled). Not desirable as CTRL-C comes handy to stop lengthy processes by the shell. To sum-up, for a safe bracketed paste, you need either: - terminal emulator to filter out ^[ and ^C Or if the terminal doesn't filter out ^[ and ^C both: - a different paste mode than xterm's \e[200~<to-paste>\e[201~ which doesn't work as <to-paste> may contain \e[201~ (something like: insert-formatted("\033[202~%S~%s", CLIPBOARD,PRIMARY,CUT_BUFFER0) would do). - zsh to disable isig. Maybe a better approach would be to query the X selection for instance with xclip/xsel where available. That can also be integrated with the zsh kill ring. I once implemented a PoC around that idea together with mouse integration https://github.com/stephane-chazelas/misc-scripts/blob/master/mouse.zsh -- Stephane ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: bracketed paste mode in xterm and urxvt 2015-06-03 20:42 ` Stephane Chazelas @ 2015-06-03 23:48 ` Oliver Kiddle 2015-06-04 7:15 ` Stephane Chazelas 0 siblings, 1 reply; 18+ messages in thread From: Oliver Kiddle @ 2015-06-03 23:48 UTC (permalink / raw) To: Stephane Chazelas; +Cc: Zsh workers Stephane Chazelas wrote: > To sum-up, for a safe bracketed paste, you need either: > > - terminal emulator to filter out ^[ and ^C > ^C is only the default interrupt character. From some basic testing, it seems you can use tcgetattr/tcsetattr on the master side of the pty. So the terminal could perhaps disable isig before writing the string and restore it afterwards. I doubt that an ssh would pass that through, however. > - a different paste mode than xterm's \e[200~<to-paste>\e[201~ which > doesn't work as <to-paste> may contain \e[201~ (something > like: insert-formatted("\033[202~%S~%s", > CLIPBOARD,PRIMARY,CUT_BUFFER0) would do). Would have been better if xterm had done it that way in the first place. As it is, stripping a fake end string should do the job. > - zsh to disable isig. > > Maybe a better approach would be to query the X selection for > instance with xclip/xsel where available. That can also be I've got a widget based on xclip. There isn't always an X connection back, however. It might be worth remembering for when copying text from firefox. The nice thing about getting bracketed paste working is that it potentially doesn't require users to learn anything new: they already know how to paste in their terminal. That's also why I think it is worth trying to include support in a form that doesn't need ohmyzsh plugins or lines in .zshrc. And putting security aside, there are other benefits like the single undo event, newlines not being accepted and the option of manipulating the string such as with shell quoting. Oliver ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: bracketed paste mode in xterm and urxvt 2015-06-03 23:48 ` Oliver Kiddle @ 2015-06-04 7:15 ` Stephane Chazelas 0 siblings, 0 replies; 18+ messages in thread From: Stephane Chazelas @ 2015-06-04 7:15 UTC (permalink / raw) To: zsh-workers 2015-06-04 01:48:25 +0200, Oliver Kiddle: > Stephane Chazelas wrote: > > To sum-up, for a safe bracketed paste, you need either: > > > > - terminal emulator to filter out ^[ and ^C > > > > ^C is only the default interrupt character. From some basic testing, it > seems you can use tcgetattr/tcsetattr on the master side of the pty. > So the terminal could perhaps disable isig before writing the string > and restore it afterwards. I doubt that an ssh would pass that through, > however. ssh (the client) disables ISIG already. It passes the ^C along and it's the remote pty line discipline that may send SIGINT to the process upon receiving that ^C, so there's nothing ssh could do there. > > - a different paste mode than xterm's \e[200~<to-paste>\e[201~ which > > doesn't work as <to-paste> may contain \e[201~ (something > > like: insert-formatted("\033[202~%S~%s", > > CLIPBOARD,PRIMARY,CUT_BUFFER0) would do). > > Would have been better if xterm had done it that way in the first place. > As it is, stripping a fake end string should do the job. zsh could use a heuristic approach similar to the one I use in the pty wrapper at http://security.stackexchange.com/questions/39118/how-can-i-protect-myself-from-this-kind-of-clipboard-abuse/52655#52655 That is detect paste by the fact that all characters come at once. Not foolproof when done by the shell as there's the case of the user typing or pasting before the prompt is issued. > > - zsh to disable isig. > > > > Maybe a better approach would be to query the X selection for > > instance with xclip/xsel where available. That can also be > > I've got a widget based on xclip. There isn't always an X connection > back, however. It might be worth remembering for when copying text from > firefox. > > The nice thing about getting bracketed paste working is that it > potentially doesn't require users to learn anything new: they already > know how to paste in their terminal. That's also why I think it is worth > trying to include support in a form that doesn't need ohmyzsh plugins or > lines in .zshrc. And putting security aside, there are other benefits > like the single undo event, newlines not being accepted and the option > of manipulating the string such as with shell quoting. [...] Agreed. ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: bracketed paste mode in xterm and urxvt 2015-06-03 15:31 ` Oliver Kiddle 2015-06-03 20:42 ` Stephane Chazelas @ 2015-06-05 10:49 ` Yuri D'Elia 2015-06-05 13:40 ` Oliver Kiddle 1 sibling, 1 reply; 18+ messages in thread From: Yuri D'Elia @ 2015-06-05 10:49 UTC (permalink / raw) To: zsh-workers On 06/03/2015 05:31 PM, Oliver Kiddle wrote: >> I do agree that mainlining this would make a lot of sense, even as a >> setopt. Or at least provide the keymap/functions needed to enable it. > > I've been using bracketed paste for a while now and would also agree. > The question is in what form to provide it? Note that I posted an > alternative mechanism in workers/29898. The patch below is a port of > that to C. Looks good to me. Actually, with this, couldn't we just disable isig while inserting the characters? If the terminal ensures that the end sequence is filtered in a bracketed paste, the shell can also be sure that anything inbetween is not user input. > With the patch as it stands, which is not meant to be final, users must > still manually enable the mode for their terminal with zle-line-init > etc (I actually append the strings to PS1/PS2/POSTEDIT). It'd certainly > possible to add a setopt option to zsh to automatically output the > enable/disable strings for bracketed paste. Testing a few ancient > terminals (xterm and dtterm on Solaris 10), they seem to have no ill > effect. Perhaps it'd be better to apply some sort of heuristics based on > terminfo, however. Any thoughts on this? I guess we can't use terminfo has no feature for this, right? > What behaviour would you want in vi-mode? What about with the region > active? Replacing the region might make sense but isn't really what > emacs or vim do. emacs disables the transient selection when pasting (which is inserted on the current cursor position). For vi I'm not sure what I would like... maybe the same. You have to enter insert mode normally, so it would make it identical in behavior. Maybe gvim is different? ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: bracketed paste mode in xterm and urxvt 2015-06-05 10:49 ` Yuri D'Elia @ 2015-06-05 13:40 ` Oliver Kiddle 2015-06-05 14:35 ` Yuri D'Elia 0 siblings, 1 reply; 18+ messages in thread From: Oliver Kiddle @ 2015-06-05 13:40 UTC (permalink / raw) To: Yuri D'Elia; +Cc: zsh-workers Yuri D'Elia wrote: > Actually, with this, couldn't we just disable isig while inserting the > characters? Unfortunately not. As Stephane indicated, the string is written in one go. The terminal driver sees and handles the interrupt character before zsh has had the chance to interpret the start sequence. It's a feature that an interrupt doesn't rely on the user program having emptied the input buffer. It might be possible to do something from a clever SIGINT handler but I doubt that could be especially reliable. I think I'd rather have xterm/urxvt strip ^C (plus a few others) and know that I shouldn't expect pasting to be safe if I use something weird. Unless someone has some other ideas? > > etc (I actually append the strings to PS1/PS2/POSTEDIT). It'd certainly > > possible to add a setopt option to zsh to automatically output the > > enable/disable strings for bracketed paste. Testing a few ancient > > terminals (xterm and dtterm on Solaris 10), they seem to have no ill > > effect. Perhaps it'd be better to apply some sort of heuristics based on > > terminfo, however. Any thoughts on this? > > I guess we can't use terminfo has no feature for this, right? Not directly but we might discern some indication from it as to whether it will regard the sequence as being an escape sequence. The important thing is that outputting \e[?2004h is harmless. Every terminal I've tried absorbs the string rather than printing some or all of it so they presumably recognise \e[? four digit number h as being an unknown escape sequence. Barring it having some other meaning, that's all we need. Taking the output of this: printf '%s %q\n' ${(kv)terminfo[(R)*[0-9](#c4)[hl]]} Shows smcup and rmcup as containing that pattern for xterm, urxvt and screen as $TERM. libvte based things use "xterm" for $TERM. Does anyone know of any other terminal that may be relevant, perhaps on a mobile phone? What about putty? > > What behaviour would you want in vi-mode? What about with the region > > active? Replacing the region might make sense but isn't really what > > emacs or vim do. > > emacs disables the transient selection when pasting (which is inserted > on the current cursor position). For vi I'm not sure what I would > like... maybe the same. You have to enter insert mode normally, so it > would make it identical in behavior. Maybe gvim is different? Replacing the selection is probably the most useful thing. Trying editors like gedit and nedit, pasting the secondary selection will replace the currently highlighted selection. GUI emacs is a bit the odd-one-out, not even grabbing the X selection but it is perhaps trying to be compatble with emacs run from a tty by default. A p command in vim does replace the selection while a middle-mouse paste uses the mouse position which isn't comparable. Oliver ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: bracketed paste mode in xterm and urxvt 2015-06-05 13:40 ` Oliver Kiddle @ 2015-06-05 14:35 ` Yuri D'Elia 2015-06-10 0:28 ` Oliver Kiddle 0 siblings, 1 reply; 18+ messages in thread From: Yuri D'Elia @ 2015-06-05 14:35 UTC (permalink / raw) To: zsh-workers On 06/05/2015 03:40 PM, Oliver Kiddle wrote: > Unfortunately not. As Stephane indicated, the string is written in one > go. The terminal driver sees and handles the interrupt character before > zsh has had the chance to interpret the start sequence. It's a feature > that an interrupt doesn't rely on the user program having emptied the > input buffer. It might be possible to do something from a clever SIGINT What if the terminal itself turns off BREAK processing during paste? > handler but I doubt that could be especially reliable. I think I'd > rather have xterm/urxvt strip ^C (plus a few others) and know that I > shouldn't expect pasting to be safe if I use something weird. Unless > someone has some other ideas? I'd rather not go down the xterm route... they've implemented a full character filtering facility in there. Which I guess is ok, since this will handle pastes for applications without any bracketing support.. but I find it to be tacked-on fix. > The important thing is that outputting \e[?2004h is harmless. Every Putty also eats it by the way. If that's the case for all terminals, I would just enabled it by default. >> emacs disables the transient selection when pasting (which is inserted >> on the current cursor position). For vi I'm not sure what I would >> like... maybe the same. You have to enter insert mode normally, so it >> would make it identical in behavior. Maybe gvim is different? > > Replacing the selection is probably the most useful thing. Trying > editors like gedit and nedit, pasting the secondary selection will > replace the currently highlighted selection. GUI emacs is a bit the > odd-one-out, not even grabbing the X selection but it is perhaps trying > to be compatble with emacs run from a tty by default. A p command in vim > does replace the selection while a middle-mouse paste uses the mouse > position which isn't comparable. I'm ambivalent to that. Replacing the selection seems pretty sound to me. ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: bracketed paste mode in xterm and urxvt 2015-06-05 14:35 ` Yuri D'Elia @ 2015-06-10 0:28 ` Oliver Kiddle 2015-06-10 4:38 ` Bart Schaefer 2015-06-10 9:44 ` Yuri D'Elia 0 siblings, 2 replies; 18+ messages in thread From: Oliver Kiddle @ 2015-06-10 0:28 UTC (permalink / raw) To: zsh-workers On 5 Jun, Yuri D'Elia wrote: > What if the terminal itself turns off BREAK processing during paste? You can try. Would be interesting. May not work when there is ssh/sshd, telnet, screen, tmux etc sat between urxvt and zsh. > Putty also eats it by the way. If that's the case for all terminals, I > would just enabled it by default. We can always add some tests later if it appears to be necessary. Any objections? I've tried quite hard to find a terminal that won't eat the sequence and found none. This links it to a new BRACKETED_PASTE option. A concern with that approach is that if logic is needed in init_term() to disable the feature, the distinction between the user explicitly disabling the feature and init_term() doing it wouldn't be clear. Any thoughts on the exact positioning of the code to print the enable/disable sequences here? Is there any way the disable sequence could get missed? Doesn't seem necessary to do anything in trashzle(). Unlike zle-line-finish (but like $POSTEDIT), this prints the disable sequence even if zle is aborted with ^C or ^D. It is also important that it comes before preexec is run because that is where you might enable bracketed paste for specific commands. This includes the previous patch. The region is now replaced if active and the widget is also bound for vi command mode. Oliver diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo index fa54024..6b32d89 100644 --- a/Doc/Zsh/options.yo +++ b/Doc/Zsh/options.yo @@ -2291,6 +2291,20 @@ cindex(enabling the beep) item(tt(BEEP) (tt(PLUS()B)) <D>)( Beep on error in ZLE. ) +pindex(BRACKETED_PASTE) +pindex(NO_BRACKETED_PASTE) +pindex(NOBRACKETED_PASTE) +cindex(bracketed paste) +cindex(enabling bracketed paste) +item(tt(BRACKETED_PASTE))( +Many terminal emulators have a feature that allow applications to +identify when text is pasted into the terminal rather than being typed +normally. If this option is set, that feature will be enabled while ZLE +is active and disabled at other times. In particular, this means that +special characters such as tabs and newlines will 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. +) pindex(COMBINING_CHARS) pindex(NO_COMBINING_CHARS) pindex(COMBININGCHARS) diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo index 16d661f..652f996 100644 --- a/Doc/Zsh/zle.yo +++ b/Doc/Zsh/zle.yo @@ -2057,6 +2057,11 @@ 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. +See also the BRACKETED_PASTE option. +) tindex(vi-cmd-mode) item(tt(vi-cmd-mode) (tt(^X^V)) (unbound) (tt(^[)))( Enter command mode; that is, select the `tt(vicmd)' keymap. diff --git a/Src/Zle/iwidgets.list b/Src/Zle/iwidgets.list index b41661a..6a07212 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_keymap.c b/Src/Zle/zle_keymap.c index c6fae25..d355f41 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 cec44c0..47b5aa5 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -1248,6 +1248,9 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish) zlecallhook(init, NULL); + if (isset(BRACKETEDPASTE)) + fputs("\e[?2004h", 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 (isset(BRACKETEDPASTE)) + fputs("\e[?2004l", shout); + if (done && !exit_pending && !errflag) zlecallhook(finish, NULL); diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c index 4669ef2..873b01b 100644 --- a/Src/Zle/zle_misc.c +++ b/Src/Zle/zle_misc.c @@ -737,6 +737,44 @@ yankpop(UNUSED(char **args)) /**/ int +bracketedpaste(UNUSED(char **args)) +{ + static const char endesc[] = "\e[201~"; + int endpos = 0; + size_t psize = 64; + char *buf, *pbuf = zalloc(psize); + size_t current = 0; + int n, next, timeout; + ZLE_STRING_T wpaste; + + 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'; + buf = zmult == 1 ? pbuf : quotestring(pbuf, NULL, QT_BACKSLASH); + zmult = 1; + wpaste = stringaszleline(buf, 0, &n, NULL, NULL); + if (region_active) + killregion(zlenoargs); + doinsert(wpaste, n); + free(pbuf); free(wpaste); + return 0; +} + +/**/ +int overwritemode(UNUSED(char **args)) { insmode ^= 1; diff --git a/Src/options.c b/Src/options.c index 78f603d..440783f 100644 --- a/Src/options.c +++ b/Src/options.c @@ -100,6 +100,7 @@ static struct optname optns[] = { {{NULL, "beep", OPT_ALL}, BEEP}, {{NULL, "bgnice", OPT_EMULATE|OPT_NONBOURNE},BGNICE}, {{NULL, "braceccl", OPT_EMULATE}, BRACECCL}, +{{NULL, "bracketedpaste", OPT_ALL}, BRACKETEDPASTE}, {{NULL, "bsdecho", OPT_EMULATE|OPT_SH}, BSDECHO}, {{NULL, "caseglob", OPT_ALL}, CASEGLOB}, {{NULL, "casematch", OPT_ALL}, CASEMATCH}, diff --git a/Src/zsh.h b/Src/zsh.h index c88c2e7..ff3793a 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -2075,6 +2075,7 @@ enum { BEEP, BGNICE, BRACECCL, + BRACKETEDPASTE, BSDECHO, CASEGLOB, CASEMATCH, ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: bracketed paste mode in xterm and urxvt 2015-06-10 0:28 ` Oliver Kiddle @ 2015-06-10 4:38 ` Bart Schaefer 2015-06-15 22:11 ` Oliver Kiddle 2015-06-10 9:44 ` Yuri D'Elia 1 sibling, 1 reply; 18+ messages in thread From: Bart Schaefer @ 2015-06-10 4:38 UTC (permalink / raw) To: zsh-workers On Jun 10, 2:28am, Oliver Kiddle wrote: } } This links it to a new BRACKETED_PASTE option. A concern with that } approach is that if logic is needed in init_term() to disable the } feature, the distinction between the user explicitly disabling the } feature and init_term() doing it wouldn't be clear. This sounds like the same dilemma that we had with ZLE_RPROMPT_INDENT, which we addressed with a variable rather than an option. This would address several problems: namespace (ZLE-specific stuff should really stop leaking into the base shell options); a place to store the string to use in case it turns out not to be the same for all terminal types; and distinguishing among unset/set/empty/non-empty semantics. So I'd vote for scrapping the setopt and adding a ZLE_BRACKETED_PASTE variable instead. ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: bracketed paste mode in xterm and urxvt 2015-06-10 4:38 ` Bart Schaefer @ 2015-06-15 22:11 ` Oliver Kiddle 2015-06-15 23:09 ` Mikael Magnusson 2015-06-16 0:20 ` Bart Schaefer 0 siblings, 2 replies; 18+ messages in thread From: Oliver Kiddle @ 2015-06-15 22:11 UTC (permalink / raw) To: zsh-workers On 9 Jun, Bart wrote: > This sounds like the same dilemma that we had with ZLE_RPROMPT_INDENT, > which we addressed with a variable rather than an option. This would > address several problems: namespace (ZLE-specific stuff should really > stop leaking into the base shell options); a place to store the string > to use in case it turns out not to be the same for all terminal types; > and distinguishing among unset/set/empty/non-empty semantics. That makes sense, thanks. So this next attempt uses ZLE_BRACKETED_PASTE_ON/OFF though I'm open to better ideas. I've not made them special, just initialised them with a call to setsparam as that seemed simple enough for the purpose. Is that reasonable or should they be special? I also looked around for places where keys are read and handled such that bracketedpaste() would not be called. I've not done anything in the case of single bytes such as for the vi r and f commands but I have added handling for the history and completion incremental searches and for the execute-named-command widget. It would be possible to avoid this special handling by adding logic to getkeycmd() so that they get a stream of self-insert widgets. That would somehow defeat the purpose of bracketed paste, however. In both the incremental search modes, backspace works like undo so the entire paste is undone. This same effect is also apparent if you press backspace after changing search direction with Ctrl-S or Ctrl-R. Oliver diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo index eb3eb36..48c973a 100644 --- a/Doc/Zsh/params.yo +++ b/Doc/Zsh/params.yo @@ -1642,6 +1642,25 @@ item(tt(ZDOTDIR))( The directory to search for shell startup files (.zshrc, etc), if not tt($HOME). ) +vindex(ZLE_BRACKETED_PASTE_ON) +vindex(ZLE_BRACKETED_PASTE_OFF) +cindex(bracketed paste) +cindex(enabling bracketed paste) +xitem(tt(ZLE_BRACKETED_PASTE_ON)) +item(tt(ZLE_BRACKETED_PASTE_OFF))( +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. + +These parameters contain 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 parameters 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 diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo index 16d661f..9066681 100644 --- a/Doc/Zsh/zle.yo +++ b/Doc/Zsh/zle.yo @@ -2057,6 +2057,11 @@ 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. +See also the ZLE_BRACKETED_PASTE_ON 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. diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c index f542066..a55567f 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; @@ -3294,17 +3278,43 @@ domenuselect(Hookdef dummy, Chdata dat) } else { msearchstr = ""; 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 b41661a..6a07212 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 cc66f99..f8aab20 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 c6fae25..d355f41 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 cec44c0..62ed157 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 = getsparam("ZLE_BRACKETED_PASTE_ON"))) + 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 = getsparam("ZLE_BRACKETED_PASTE_OFF"))) + fputs(bracket, shout); + if (done && !exit_pending && !errflag) zlecallhook(finish, NULL); @@ -2028,6 +2034,9 @@ setup_(UNUSED(Module m)) clwords = (char **) zshcalloc((clwsize = 16) * sizeof(char *)); + setsparam("ZLE_BRACKETED_PASTE_ON", ztrdup("\033[?2004h")); + setsparam("ZLE_BRACKETED_PASTE_OFF", ztrdup("\033[?2004l")); + return 0; } diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c index 4669ef2..ef9d0a8 100644 --- a/Src/Zle/zle_misc.c +++ b/Src/Zle/zle_misc.c @@ -736,6 +736,54 @@ yankpop(UNUSED(char **args)) } /**/ +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(UNUSED(char **args)) +{ + int n; + ZLE_STRING_T wpaste; + char *pbuf = bracketedstring(); + + 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 +1312,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; ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: bracketed paste mode in xterm and urxvt 2015-06-15 22:11 ` Oliver Kiddle @ 2015-06-15 23:09 ` Mikael Magnusson 2015-06-16 0:20 ` Bart Schaefer 1 sibling, 0 replies; 18+ messages in thread From: Mikael Magnusson @ 2015-06-15 23:09 UTC (permalink / raw) To: Oliver Kiddle; +Cc: zsh workers On Tue, Jun 16, 2015 at 12:11 AM, Oliver Kiddle <okiddle@yahoo.co.uk> wrote: > On 9 Jun, Bart wrote: >> This sounds like the same dilemma that we had with ZLE_RPROMPT_INDENT, >> which we addressed with a variable rather than an option. This would >> address several problems: namespace (ZLE-specific stuff should really >> stop leaking into the base shell options); a place to store the string >> to use in case it turns out not to be the same for all terminal types; >> and distinguishing among unset/set/empty/non-empty semantics. > > That makes sense, thanks. > > So this next attempt uses ZLE_BRACKETED_PASTE_ON/OFF though I'm open to > better ideas. > I've not made them special, just initialised them with a call to > setsparam as that seemed simple enough for the purpose. Is that > reasonable or should they be special? > > I also looked around for places where keys are read and handled such > that bracketedpaste() would not be called. I've not done anything in > the case of single bytes such as for the vi r and f commands but I have > added handling for the history and completion incremental searches and > for the execute-named-command widget. It would be possible to avoid this > special handling by adding logic to getkeycmd() so that they get a > stream of self-insert widgets. That would somehow defeat the > purpose of bracketed paste, however. > > In both the incremental search modes, backspace works like undo so the > entire paste is undone. This same effect is also apparent if you press > backspace after changing search direction with Ctrl-S or Ctrl-R. > > +int > +bracketedpaste(UNUSED(char **args)) > +{ > + int n; > + ZLE_STRING_T wpaste; > + char *pbuf = bracketedstring(); > + > + wpaste = stringaszleline((zmult == 1) ? pbuf : > + quotestring(pbuf, NULL, QT_BACKSLASH), 0, &n, NULL, NULL); > + zmult = 1; This feature appears to be undocumented? I also think the documentation for the widget should list the default bindings, as other widgets do. It might also be nice if the widget could take a parameter as an argument to store the text in, rather than insert it into the command line always. -- Mikael Magnusson ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: bracketed paste mode in xterm and urxvt 2015-06-15 22:11 ` Oliver Kiddle 2015-06-15 23:09 ` Mikael Magnusson @ 2015-06-16 0:20 ` Bart Schaefer 2015-06-16 17:12 ` Oliver Kiddle 1 sibling, 1 reply; 18+ messages in thread From: Bart Schaefer @ 2015-06-16 0:20 UTC (permalink / raw) To: zsh-workers On Jun 16, 12:11am, Oliver Kiddle wrote: } } So this next attempt uses ZLE_BRACKETED_PASTE_ON/OFF though I'm open to } better ideas. I might have chosen a single two-valued array and require it to either be empty or to have two values (whether "exactly" or "at least" is less important) so that it's harder e.g. to accidentally begin bracketed paste mode and never exit from it. } I've not made them special, just initialised them with a call to } setsparam as that seemed simple enough for the purpose. Is that } reasonable or should they be special? Mostly, variables only need to be special when they have a custom GSU structure, e.g., ZLE_RROMPT_INDENT keeps the internal rprompt_indent value updated because it's accessed frequently (so calling getsparam() is too inefficient), so it is special. ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: bracketed paste mode in xterm and urxvt 2015-06-16 0:20 ` Bart Schaefer @ 2015-06-16 17:12 ` Oliver Kiddle 2015-06-16 20:26 ` Bart Schaefer 0 siblings, 1 reply; 18+ messages in thread From: Oliver Kiddle @ 2015-06-16 17:12 UTC (permalink / raw) To: zsh-workers Bart wrote: > I might have chosen a single two-valued array and require it to either > be empty or to have two values (whether "exactly" or "at least" is less > important) so that it's harder e.g. to accidentally begin bracketed paste > mode and never exit from it. That does sound better. As an array, should the name be lowercase - zle_bracketed_paste? Mikael wrote: > This feature appears to be undocumented? I also think the > documentation for the widget should list the default bindings, as > other widgets do. I didn't list the bindings because they don't correspond to actual keys. It seems more of an implementation detail that may be adapted in future if other terminal emulators do things differently. I'm not especially bothered, however. > It might also be nice if the widget could take a parameter as an > argument to store the text in, rather than insert it into the command > line always. That's a good idea. Makes it quite easy to write a custom widget in terms of the default one. Besides the existing quoting use case, the only other idea that comes to mind is to strip comments out so that scripts can be copied without having to set interactive_comments. This patch goes on top of the previous one rather than replacing it. Thanks for the feedback. Oliver diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo index 48c973a..e209162 100644 --- a/Doc/Zsh/params.yo +++ b/Doc/Zsh/params.yo @@ -1642,12 +1642,10 @@ item(tt(ZDOTDIR))( The directory to search for shell startup files (.zshrc, etc), if not tt($HOME). ) -vindex(ZLE_BRACKETED_PASTE_ON) -vindex(ZLE_BRACKETED_PASTE_OFF) +vindex(zle_bracketed_paste) cindex(bracketed paste) cindex(enabling bracketed paste) -xitem(tt(ZLE_BRACKETED_PASTE_ON)) -item(tt(ZLE_BRACKETED_PASTE_OFF))( +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 @@ -1655,10 +1653,10 @@ 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. -These parameters contain 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 parameters has the effect of ensuring that bracketed paste +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) diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo index 9066681..30675b4 100644 --- a/Doc/Zsh/zle.yo +++ b/Doc/Zsh/zle.yo @@ -2060,7 +2060,12 @@ 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. -See also the ZLE_BRACKETED_PASTE_ON parameter. +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 zle_bracketed_paste parameter. ) tindex(vi-cmd-mode) item(tt(vi-cmd-mode) (tt(^X^V)) (unbound) (tt(^[)))( diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 62ed157..7ccfb68 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, *bracket; + char *s, **bracket; int old_errno = errno; int tmout = getiparam("TMOUT"); @@ -1248,8 +1248,8 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish) zlecallhook(init, NULL); - if ((bracket = getsparam("ZLE_BRACKETED_PASTE_ON"))) - fputs(bracket, shout); + if ((bracket = getaparam("zle_bracketed_paste")) && arrlen(bracket) == 2) + fputs(*bracket, shout); zrefresh(); @@ -1260,8 +1260,8 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish) "ZLE_VARED_ABORTED" : "ZLE_LINE_ABORTED", zlegetline(NULL, NULL)); - if ((bracket = getsparam("ZLE_BRACKETED_PASTE_OFF"))) - fputs(bracket, shout); + if ((bracket = getaparam("zle_bracketed_paste")) && arrlen(bracket) == 2) + fputs(bracket[1], shout); if (done && !exit_pending && !errflag) zlecallhook(finish, NULL); @@ -2010,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; @@ -2034,8 +2036,10 @@ setup_(UNUSED(Module m)) clwords = (char **) zshcalloc((clwsize = 16) * sizeof(char *)); - setsparam("ZLE_BRACKETED_PASTE_ON", ztrdup("\033[?2004h")); - setsparam("ZLE_BRACKETED_PASTE_OFF", ztrdup("\033[?2004l")); + 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 ef9d0a8..c2fb2e7 100644 --- a/Src/Zle/zle_misc.c +++ b/Src/Zle/zle_misc.c @@ -767,19 +767,23 @@ bracketedstring() /**/ int -bracketedpaste(UNUSED(char **args)) +bracketedpaste(char **args) { - int n; - ZLE_STRING_T wpaste; char *pbuf = bracketedstring(); - 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); + 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; } ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: bracketed paste mode in xterm and urxvt 2015-06-16 17:12 ` Oliver Kiddle @ 2015-06-16 20:26 ` Bart Schaefer 2015-06-17 10:45 ` Oliver Kiddle 0 siblings, 1 reply; 18+ messages in thread From: Bart Schaefer @ 2015-06-16 20:26 UTC (permalink / raw) To: zsh-workers On Jun 16, 7:12pm, Oliver Kiddle wrote: } Subject: Re: bracketed paste mode in xterm and urxvt } } Bart wrote: } > I might have chosen a single two-valued array } } That does sound better. As an array, should the name be lowercase - } zle_bracketed_paste? I don't have a strong opinion -- lowercase is probably fine. } Mikael wrote: } > documentation for the widget should list the default bindings } } I didn't list the bindings because they don't correspond to actual } keys. [...] } This patch goes on top of the previous one rather than replacing it. Speaking of the bindings in the previous patch -- Src/Zle/zle_keymap.c -- should those be hardwired? Perhaps an optional third element of the zle_bracketed_paste array could be the string for the key binding. -- Barton E. Schaefer ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: bracketed paste mode in xterm and urxvt 2015-06-16 20:26 ` Bart Schaefer @ 2015-06-17 10:45 ` Oliver Kiddle 2015-06-17 15:04 ` Bart Schaefer 0 siblings, 1 reply; 18+ messages in thread From: Oliver Kiddle @ 2015-06-17 10:45 UTC (permalink / raw) To: zsh-workers Bart wrote: > Speaking of the bindings in the previous patch -- Src/Zle/zle_keymap.c > -- should those be hardwired? Perhaps an optional third element of the > zle_bracketed_paste array could be the string for the key binding. Given a situation of someone wanting to assign to just that third element to have a different key binding, we would have to initialise zle_bracketed_paste outside of the zle module in order for it to occur earlier than both the assignment in .zshrc and the key binding. Or you'd have to dynamically update the bindings when the variable is set. That doesn't really add anything given that changing key bindings is easily done directly. I'm not really sure that it would achieve anything other than allow us to feel less bad about the hardwired escape sequences. Oliver ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: bracketed paste mode in xterm and urxvt 2015-06-17 10:45 ` Oliver Kiddle @ 2015-06-17 15:04 ` Bart Schaefer 0 siblings, 0 replies; 18+ messages in thread From: Bart Schaefer @ 2015-06-17 15:04 UTC (permalink / raw) To: zsh-workers On Jun 17, 12:45pm, Oliver Kiddle wrote: } } Bart wrote: } > Perhaps an optional third element of the } > zle_bracketed_paste array could be the string for the key binding. } } doesn't really add anything given that changing key bindings is easily } done directly. OK, I buy that. Document under the widget that changing the binding is how you do this? ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: bracketed paste mode in xterm and urxvt 2015-06-10 0:28 ` Oliver Kiddle 2015-06-10 4:38 ` Bart Schaefer @ 2015-06-10 9:44 ` Yuri D'Elia 1 sibling, 0 replies; 18+ messages in thread From: Yuri D'Elia @ 2015-06-10 9:44 UTC (permalink / raw) To: zsh-workers On 06/10/2015 02:28 AM, Oliver Kiddle wrote: > On 5 Jun, Yuri D'Elia wrote: >> What if the terminal itself turns off BREAK processing during paste? > > You can try. Would be interesting. May not work when there is ssh/sshd, > telnet, screen, tmux etc sat between urxvt and zsh. I will give it a try. Doesn't sound complicated to implement (easier than read ssh source code anyway..). >From reading termios(8) though, if we disable BREAK a \0 is emitted in his place. >> Putty also eats it by the way. If that's the case for all terminals, I >> would just enabled it by default. > > We can always add some tests later if it appears to be necessary. Any > objections? > I've tried quite hard to find a terminal that won't eat the sequence and > found none. I have an old SGI Octane sitting somewhere, with IRIX 6.5... but do we really want to support it ? ;) I would say it's really better if this was enabled by default and see if there's any report coming in. ^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2015-06-17 15:04 UTC | newest] Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- [not found] <BANLkTikh_-+L2W5=Yfu7h7iAe5CcpP6fxw@mail.gmail.com> [not found] ` <CAFOazAOfk=Sq-smkMGzJKO4b7jMb_1_m4vXXn8twoVA2wV55YA@mail.gmail.com> [not found] ` <55677AF5.50709@thequod.de> [not found] ` <mk9dc0$p0$1@ger.gmane.org> [not found] ` <CABZhJg_5p8BLbq82s_wVtsPdD5hVtk-cPg6fNxzbSs4Vg00SOw@mail.gmail.com> [not found] ` <mkmjfu$3h0$1@ger.gmane.org> [not found] ` <CAHYJk3T3dVdN5qDMecPAH_ALLBYNntW0QVdPMh50Lo_ULeWP6w__21110.9288772152$1433333265$gmane$org@mail.gmail.com> 2015-06-03 12:43 ` bracketed paste mode in xterm and urxvt Stephane Chazelas 2015-06-03 15:31 ` Oliver Kiddle 2015-06-03 20:42 ` Stephane Chazelas 2015-06-03 23:48 ` Oliver Kiddle 2015-06-04 7:15 ` Stephane Chazelas 2015-06-05 10:49 ` Yuri D'Elia 2015-06-05 13:40 ` Oliver Kiddle 2015-06-05 14:35 ` Yuri D'Elia 2015-06-10 0:28 ` Oliver Kiddle 2015-06-10 4:38 ` Bart Schaefer 2015-06-15 22:11 ` Oliver Kiddle 2015-06-15 23:09 ` Mikael Magnusson 2015-06-16 0:20 ` Bart Schaefer 2015-06-16 17:12 ` Oliver Kiddle 2015-06-16 20:26 ` Bart Schaefer 2015-06-17 10:45 ` Oliver Kiddle 2015-06-17 15:04 ` Bart Schaefer 2015-06-10 9:44 ` Yuri D'Elia
Code repositories for project(s) associated with this public inbox https://git.vuxu.org/mirror/zsh/ This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).