From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 19912 invoked by alias); 28 Jun 2016 14:53:30 -0000 Mailing-List: contact zsh-workers-help@zsh.org; run by ezmlm Precedence: bulk X-No-Archive: yes List-Id: Zsh Workers List List-Post: List-Help: X-Seq: 38770 Received: (qmail 1848 invoked from network); 28 Jun 2016 14:53:28 -0000 X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on f.primenet.com.au X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,FREEMAIL_FROM, T_DKIM_INVALID autolearn=ham autolearn_force=no version=3.4.1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.co.uk; s=s2048; t=1467125212; bh=Bn8CrUi+kGodwjnSl9hTCXN67fBbuYA2Fh32Z/jTRTI=; h=From:To:Subject:Date:From:Subject; b=ZTSolkLQ7wmWKgj2igNY+NXI/ttAbFd3cisfhW0CeGlqsn8p5tx1VaVy1Y9MIs0HXbrh+j81H2Rbo9fAwyn8XUnd4ww8a7MVIWL7cexd1ZpazeIm0Mlmzwm+/8DdJLmfGGwsNqrgxVhs6yuifYm/HtgVwiPLuH/tvOxUKZxHCCgudizsiImPnLYf7dp20iafXEazCMzGDLolP8ToqxYB2WKPz4/+b/Ixi++oz5oINg43FO0DR7q07o41jp3oASodg6x/FG42MtgLBGdHxUYIqcMM/oODg1AO/ABjt3dgpIEJjP8kK5lEgXfpVtgMg1v6j9MTfGERpmY9ItGBaUH6Ow== X-Yahoo-Newman-Id: 658207.5040.bm@smtp103.mail.ir2.yahoo.com X-Yahoo-Newman-Property: ymail-3 X-YMail-OSG: S4AZkNsVM1kBYs0.rJa4XnlLGfaBIrab8IF87xqm5l.T.Li yo.Ki5QRUmjw8JIAuBQslAAKmcKxeM7LRpLO2F_IQMO7H0OUWVSK.O.H2NcF 3hmkU94l8bmcLASnjpZHoRhOaEmUAPt48Bpl8M34J8iR8bUYQNKEpvhA6cyf e5nLL6FptP0OnQmAn2ldFzX_5Z2DkADNDKgApoTYHh8g7y6gCJA60W4Z4SPL uFBoQ3dxeVbcDLBVTcIQNca_7WG9JVcIwiUwjDnbxjcrjPAnUltJ.covPzv. zicyf2O2kH9ZBeqrdzAfJjUj4iSRgWmXlsOFG1YNkTZpZ7veomOo8bEiKWH_ ZRo4ovDwp8KlsQL8ohVWwRZBxsWAszNAwAp9k_mXXIQ5STjumjQtWlyC1RCN mwYYESlu5F4nQBhaaoLrxYYy6vxpRmGaUA.SyMcfsOn64cAuossLV6rrlKXM 5QY1VRpBEotT.5cbCSUbESy_.ukGJKn3Vhv1nKNLsGLFgaFRmqJxNNVqLRfu 3HUqWCUS3vRNE7ppPBoATyxl_0QZuhY9OO_8.hd3Hptk- X-Yahoo-SMTP: opAkk_CswBAce_kJ3nIPlH80cJI- From: Oliver Kiddle To: Zsh workers Subject: PATCH: vi-mode case-manipulation MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-ID: <2678.1467125211.1@thecus.kiddle.eu> Date: Tue, 28 Jun 2016 16:46:51 +0200 Message-ID: <2679.1467125211@thecus.kiddle.eu> This adds vi upper/lowercase widgets (gU / gu) in C form. There isn't much difference to the shell widgets but it is possible to have the keys bound by default and they aren't afflicted by KEYTIMEOUT problems. That means guu and gUU work as aliases for gugu and gUgU. For consistency with the naming of the emacs widgets, they are named vi-up-case and vi-down-case. Perhaps select-bracketed and quoted would also be better in C form with something simpler and less likely to be missed by a vim user serving as a shell widget example. I think there is some value in providing a shell widget example of how to read a vi movement. This includes vi-pipe which is like ! in vi. It uses vi-delete instead of vi-change followed by vi-cmd-mode. Perhaps there was a reason for using vi-change in my original case change widgets but if so, I've forgotten what it was. Oliver diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo index 53ae96d..f1208e8 100644 --- a/Doc/Zsh/contrib.yo +++ b/Doc/Zsh/contrib.yo @@ -2968,6 +2968,17 @@ and aliases `tt(globurl)' to `tt(noglob urlglobber)'. This function takes a local URL apart, attempts to pattern-match the local file portion of the URL path, and then puts the results back into URL format again. ) +tindex(vi-pipe) +item(tt(vi-pipe))( +This function reads a movement command from the keyboard and then +prompts for an external command. The part of the buffer covered by +the movement is piped to the external command and then replaced by +the command's output. If the movement command is bound to vi-pipe, +the current line is used. + +The function serves as an example for reading a vi movement command +from within a user-defined widget. +) tindex(which-command) item(tt(which-command))( This function is a drop-in replacement for the builtin widget diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo index 80d3f39..1bae0cc 100644 --- a/Doc/Zsh/zle.yo +++ b/Doc/Zsh/zle.yo @@ -1781,6 +1781,13 @@ tindex(down-case-word) item(tt(down-case-word) (tt(ESC-L ESC-l)) (unbound) (unbound))( Convert the current word to all lowercase and move past it. ) +tindex(vi-down-case) +item(tt(vi-down-case)) ((unbound) (tt(gu)) (unbound))( +Read a movement command from the keyboard, and convert all characters +from the cursor position to the endpoint of the movement to lowercase. +If the movement command is tt(vi-down-case), swap the case of all +characters on the current line. +) tindex(kill-word) item(tt(kill-word) (tt(ESC-D ESC-d)) (unbound) (unbound))( Kill the current word. @@ -1946,6 +1953,13 @@ tindex(vi-unindent) item(tt(vi-unindent) (unbound) (tt(<)) (unbound))( Unindent a number of lines. ) +tindex(vi-up-case) +item(tt(vi-up-case)) ((unbound) (tt(gU)) (unbound))( +Read a movement command from the keyboard, and convert all characters +from the cursor position to the endpoint of the movement to lowercase. +If the movement command is tt(vi-up-case), swap the case of all +characters on the current line. +) tindex(up-case-word) item(tt(up-case-word) (tt(ESC-U ESC-u)) (unbound) (unbound))( Convert the current word to all caps and move past it. diff --git a/Functions/Zle/vi-pipe b/Functions/Zle/vi-pipe new file mode 100644 index 0000000..a28f211 --- /dev/null +++ b/Functions/Zle/vi-pipe @@ -0,0 +1,31 @@ +# Example of a widget that takes a vi motion + +# Filter part of buffer corresponding to a vi motion through an external +# program. + +# To enable with vi compatible bindings use: +# autoload -Uz vi-pipe +# bindkey -a '!' vi-pipe + +autoload -Uz read-from-minibuffer +local _save_cut="$CUTBUFFER" REPLY + +# Use the standard vi-delete to accept a vi motion. +zle .vi-delete || return +read-from-minibuffer "!" +local _save_cur=$CURSOR + +# cut buffer contains the deleted text and can be modified +CUTBUFFER="$(eval $REPLY <<<$CUTBUFFER)" + +# put the modified text back in position. +if [[ CURSOR -eq 0 || $BUFFER[CURSOR] = $'\n' ]]; then + # at the beginning of a line, vi-delete won't have moved the cursor + # back to a previous line + zle .vi-put-before -n 1 +else + zle .vi-put-after -n 1 +fi + +# restore cut buffer and cursor to the start of the range +CUTBUFFER="$_save_cut" CURSOR="$_save_cur" diff --git a/Src/Zle/iwidgets.list b/Src/Zle/iwidgets.list index 2b2654c..58310cd 100644 --- a/Src/Zle/iwidgets.list +++ b/Src/Zle/iwidgets.list @@ -143,6 +143,7 @@ "vi-delete", videlete, ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_VIOPER "vi-delete-char", videletechar, ZLE_KEEPSUFFIX "vi-digit-or-beginning-of-line", vidigitorbeginningofline, 0 +"vi-down-case", vidowncase, ZLE_LASTCOL | ZLE_VIOPER "vi-down-line-or-history", vidownlineorhistory, ZLE_LINEMOVE "vi-end-of-line", viendofline, ZLE_LASTCOL "vi-fetch-history", vifetchhistory, ZLE_LINEMOVE @@ -188,6 +189,7 @@ "vi-swap-case", viswapcase, ZLE_LASTCOL "vi-undo-change", viundochange, ZLE_KEEPSUFFIX "vi-unindent", viunindent, ZLE_LASTCOL | ZLE_VIOPER +"vi-up-case", viupcase, ZLE_LASTCOL | ZLE_VIOPER "vi-up-line-or-history", viuplineorhistory, ZLE_LINEMOVE "vi-yank", viyank, ZLE_LASTCOL | ZLE_VIOPER "vi-yank-eol", viyankeol, 0 diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c index f547dbf..3db4207 100644 --- a/Src/Zle/zle_keymap.c +++ b/Src/Zle/zle_keymap.c @@ -1374,8 +1374,11 @@ default_bindings(void) bindkey(amap, "ge", refthingy(t_vibackwardwordend), NULL); bindkey(amap, "gE", refthingy(t_vibackwardblankwordend), NULL); bindkey(amap, "gg", refthingy(t_beginningofbufferorhistory), NULL); - bindkey(amap, "g~", refthingy(t_vioperswapcase), NULL); + bindkey(amap, "gu", refthingy(t_vidowncase), NULL); + bindkey(amap, "gU", refthingy(t_viupcase), NULL); bindkey(amap, "g~~", NULL, "g~g~"); + bindkey(amap, "guu", NULL, "gugu"); + bindkey(amap, "gUU", NULL, "gUgU"); /* emacs mode: arrow keys */ add_cursor_key(emap, TCUPCURSOR, t_uplineorhistory, 'A'); diff --git a/Src/Zle/zle_vi.c b/Src/Zle/zle_vi.c index 953af24..baa2064 100644 --- a/Src/Zle/zle_vi.c +++ b/Src/Zle/zle_vi.c @@ -731,6 +731,52 @@ vioperswapcase(UNUSED(char **args)) /**/ int +viupcase(UNUSED(char **args)) +{ + int oldcs, c2, ret = 1; + + /* get the range */ + startvichange(1); + if ((c2 = getvirange(0)) != -1) { + oldcs = zlecs; + /* covert the case of all letters within range */ + while (zlecs < c2) { + zleline[zlecs] = ZC_toupper(zleline[zlecs]); + INCCS(); + } + /* go back to the first line of the range */ + zlecs = oldcs; + ret = 0; + } + vichgflag = 0; + return ret; +} + +/**/ +int +vidowncase(UNUSED(char **args)) +{ + int oldcs, c2, ret = 1; + + /* get the range */ + startvichange(1); + if ((c2 = getvirange(0)) != -1) { + oldcs = zlecs; + /* convert the case of all letters within range */ + while (zlecs < c2) { + zleline[zlecs] = ZC_tolower(zleline[zlecs]); + INCCS(); + } + /* go back to the first line of the range */ + zlecs = oldcs; + ret = 0; + } + vichgflag = 0; + return ret; +} + +/**/ +int virepeatchange(UNUSED(char **args)) { /* make sure we have a change to repeat */