Subject: PATCH: vi-pipe (Re: PATCH: vi-mode case-manipulation)
From: Oliver Kiddle <[email-masked]>
To: Zsh workers <[email-masked]>
Date: Sun, 24 Jul 2016 08:34:59 +0200
List-Id: Zsh Workers List <zsh-workers.zsh.org>

On 29 Jun, Bart wrote:
> } 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.
>
> I think you've forgotten an "emulate zsh" or the like, since you're
> referencing $REPLY and $CUTBUFFER un-quoted.  (Sorry I didn't get to
> this before you'd committed.)

Is compatibility ok in the following? RHS of the CUTBUFFER assignment
now has no outer quotes but I think that's ok as it is the rhs of an
assignment.

I also discovered the reason for having used vi-change followed by
vi-cmd-mode in my original case conversion widgets instead of
vi-delete - it has a subtle effect on cursor positioning. Though
we've got a bug that vi-cmd-mode in the middle of a widget will act
like a split-undo.

Furthermore, ! in real vi forces the movement to act linewise. We can force
this by ungetting a V before calling vi-change.

I had thought ! a good example for a shell-based widget because I
couldn't imagine anyone wanting mappings that make it a prefix so
the lack if the VI_OPER flag wouldn't matter. It now occurs to me that
  noremap !o o<Esc>!!
and similarly for O is a useful shortcut. Zsh equivalent if you can
type faster than KEYTIMEOUT is:
  bindkey -as '!o' $'o\e!!'
Or maybe there's a better way to insert the output of a command in vim?

Oliver

diff --git a/Functions/Zle/vi-pipe b/Functions/Zle/vi-pipe
index 2d2e295..028f1e1 100644
--- a/Functions/Zle/vi-pipe
+++ b/Functions/Zle/vi-pipe
@@ -7,16 +7,21 @@
 #   autoload -Uz vi-pipe
 #   bindkey -a '!' vi-pipe
 
+setopt localoptions noksharrays
+
 autoload -Uz read-from-minibuffer
 local _save_cut="$CUTBUFFER" REPLY
 
-# Use the standard vi-delete to accept a vi motion.
-zle .vi-delete || return
+# force movement to default to line mode
+zle -U V
+# Use the standard vi-change to accept a vi motion.
+zle .vi-change || return
 read-from-minibuffer "!"
+zle .vi-cmd-mode
 local _save_cur=$CURSOR
 
 # cut buffer contains the deleted text and can be modified
-CUTBUFFER="$(eval $REPLY <<<$CUTBUFFER)"
+CUTBUFFER=$(eval "$REPLY" <<<"$CUTBUFFER")
 
 # put the modified text back in position.
 if [[ CURSOR -eq 0 || $BUFFER[CURSOR] = $'\n' ]]; then