Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Strange behaviour of setopt and binkey in a widget

On Tue, 20 Apr 2010 11:02:29 +0200
Mike Perdide <mike.perdide@xxxxxxxxx> wrote:
> Hello zsh users,
> I'm trying to customize the behaviour of CTRL-D in certain conditions
> and I 'm observing strange behaviours from zsh.
> Here is what I do :
> -------------- From my .zshrc ---------------
> widg0() { echo "not really exiting"; }
> zle -N widg0
> widg1() { setopt ignoreeof; bindkey "^D" widg0; }
> widg2() { unsetopt ignoreeof; bindkey -r "^D"; }
> zle -N widg1
> zle -N widg2
> bindkey "^O" widg1
> bindkey "^P" widg2
> -------------- Starting from a bash shell :
> [22:49] :~$ zsh
> north.~% <CTRL-O> <CTRL-D>
> zsh: use 'exit' to exit.
> north.~% <CTRL-D>not really exiting
>           !!! First strange behaviour : the prompt is not redrawn. At
> this point I press <ENTER> to get my prompt back :

This isn't actually strange at all if you consider that all widg0 done is
echo "not really exiting" to the screen.  You haven't told the shell to
redraw the prompt.  The way to do this is tell ZLE you're taking over the
display for a bit, so that when the widget exits it will redraw the prompt

widg0() {
  zle -I
  echo "not really exiting"

> north.~% <CTRL-P> <CTRL-D>
> !!! The previous ligne is rewritten with these two :
> [22:53] :~$
> zsh: use 'exit' to exit

This actually did exit the shell for me (which is what you want, although
I'm not sure now much I expected it given the ^D wasn't bound to anything
any more and it's being processed by zsh, not handled directly as EOF which
zsh has to synthesise).  Does "stty -a" show that ^D is the EOF character?

I once wrote a widget delete-char-or-list-new, which is a reimplementation
of what ^D usually does with Emacs bindings with slightly different
behaviour.  The interesting thing is I had to put in the EOF handling
directly.  I don't know if it's any use to you.  Note that unlike the
default shell behaviour you need to tell it the maximum number of "EOF"s to
ignore, e.g.

  zstyle ':zle:*' ignore-eof-count 10"

The message is also customisable, e.g.

  zstyle ':zle:*' ignore-eof-msg "ignoring eof (%c / %m times)"

I tried this and it seemed to work...

#start delete-char-or-list-new
# This is supposed to work like delete-char-or-list, except that the
# list generated is always new.

if [[ -z $BUFFER ]]; then
  integer eofmax ignoreeof
  if zstyle -s ":zle:$WIDGET" ignore-eof-count eofmax; then
    [[ -o ignore_eof ]] && ignoreeof=1
  if [[ -n $ignoreeof ]]; then
    integer -g __eof_count

    if [[ eofmax -le 0 ]]; then
    elif [[ $LASTWIDGET = $WIDGET ]]; then
      if (( ++__eof_count == eofmax )); then

    zmodload -i zsh/zutil

    local fmt msg what=exit
    zstyle -s ":zle:$WIDGET" ignore-eof-msg fmt ||
    fmt="zsh: use '%s' to %s."
    [[ -o login ]] && what=logout
    zformat -f msg $fmt s:$what m:$eofmax c:$__eof_count
    zle -M $msg

    return 1

# The <= 0 (formally just != 0) is so that negative prefixes used in
# Perforce completion force a new listing.

if (( ${NUMERIC:-0} <= 0 )); then

zle delete-char-or-list
#end delete-char-or-list-new

Peter Stephenson <pws@xxxxxxx>            Software Engineer
Tel: +44 (0)1223 692070                   Cambridge Silicon Radio Limited
Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, UK

Member of the CSR plc group of companies. CSR plc registered in England and Wales, registered number 4187346, registered office Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, United Kingdom

Messages sorted by: Reverse Date, Date, Thread, Author