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

Re: PATCH: exit after 10 EOF's



Here is a simplification to replace the previous broken ignore_eof
behaviour (sometimes you get EOF after 10 ^D's and a message, sometimes
[in the editor] you get the same message but it doesn't exit and doesn't
call the bound widget, some [non-completion] widgets suppress the
message and work normally, some [completion] widgets don't suppress the
message and don't run...  I may have got some of that wrong, and I don't
particularly care.)  It backs off the previous patch which removed one
of the four behaviours but modified one of the others.

This should cover all bases.  The basic rule is that in ZLE ignore_eof
means the EOF character is always treated as a normal key.  If you want
any other behaviour you can use a widget.  I've supplied one which
should cover the most likely desired outcomes (though I suspect I've
made the documentation confusing).

I hope this makes fluffy bunnies gambol in the field.

If I commit it, I will remove the "#if 0" chunks properly.

Index: Doc/Zsh/contrib.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/contrib.yo,v
retrieving revision 1.36
diff -u -r1.36 contrib.yo
--- Doc/Zsh/contrib.yo	29 Jul 2004 14:22:21 -0000	1.36
+++ Doc/Zsh/contrib.yo	16 Sep 2004 14:43:20 -0000
@@ -561,6 +561,44 @@
 spots.  It can be invoked repeatedly to cycle between all positions
 reported by the completion system.
 )
+tindex(delete-char-or-list replacement)
+item(tt(delete-char-or-list))(
+This is a drop-in replacement for the builtin zle widget of the same name.
+The only difference appears when it is executed on an empty line;
+otherwise, it is indistinguishable from tt(delete-char-or-list).  It
+mimics the use of the default binding tt(\C-d) as an end-of-file character,
+but in a more configurable way.
+
+Assuming the binding is to the configured end-of-file character, the
+function is only useful if the option tt(IGNORE_EOF) is set; otherwise
+the shell will exit before the widget is called.  However, it is
+possible to disable the character with `tt(stty eof "^-")'.  In that case,
+the option tt(IGNORE_EOF) is respected.
+
+If tt(IGNORE_EOF) is set, or the style tt(ignore-eof-count) is set to an
+integer, the function prints a message and does not exit the shell.  If
+neither is set, the function exits the shell.
+
+If the style tt(ignore-eof-count) is set to an integer greater than zero,
+this gives a count of times the widget must be executed consecutively
+before the shell will be executed.
+
+The message to be printed may be customized by setting the style
+tt(ignore-eof-msg) for the context tt(:zle:)var(widget).  The value may
+contain tt(%s), which will be replaced by tt(logout) for a login shell,
+otherwise tt(exit); tt(%m), which will be replaced by the value of
+tt(ignore-eof-count); and tt(%c), which will be replaced by the count of
+consecutive times the widget has been executed.  The default message
+is `tt(zsh: use '%s' to %s.)'.
+
+The name of the widget is significant as this widget tries to invoke
+tt(.)var(widget) to implement the standard (non-EOF) behavior.  Hence this
+widget may be used to replace other bindings for tt(\C-d) (or, indeed, any
+other key used as an end-of-file character).
+
+The styles are looked up in the context tt(:zle:)var(widget), where
+var(widget) is the name of the widget.
+)
 tindex(edit-command-line)
 item(tt(edit-command-line))(
 Edit the command line using your visual editor, as in tt(ksh).
Index: Doc/Zsh/options.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/options.yo,v
retrieving revision 1.35
diff -u -r1.35 options.yo
--- Doc/Zsh/options.yo	3 Sep 2004 09:47:48 -0000	1.35
+++ Doc/Zsh/options.yo	16 Sep 2004 14:43:21 -0000
@@ -698,13 +698,16 @@
 item(tt(IGNORE_EOF) (tt(-7)))(
 Do not exit on end-of-file.  Require the use
 of tt(exit) or tt(logout) instead.
-However, ten consecutive EOFs will cause the shell to exit anyway,
+However, unless the Zsh Line Editor is active,
+ten consecutive EOFs will cause the shell to exit anyway,
 to avoid the shell hanging if its tty goes away.
 
-Also, if this option is set and the Zsh Line Editor is used, widgets
-implemented by shell functions can be bound to EOF (normally
-Control-D) without printing the normal warning message.  This works
-only for normal widgets, not for completion widgets.
+In the line editor, if the option is set end-of-file characters are
+always handled as ordinary characters.  (The line editor detects
+genuine end-of-file conditions separately.)  It is possible to implement
+a widget to handle this is some other way.  See
+the example widget tt(delete-char-or-list) in ifzman(zmanref(zshcontrib))\
+ifnzman(noderef(ZLE Functions))
 )
 pindex(INTERACTIVE_COMMENTS)
 cindex(comments, in interactive shells)
Index: Functions/Zle/delete-char-or-list
===================================================================
RCS file: Functions/Zle/delete-char-or-list
diff -N Functions/Zle/delete-char-or-list
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Functions/Zle/delete-char-or-list	16 Sep 2004 14:43:21 -0000
@@ -0,0 +1,39 @@
+# A drop-in replacement for delete-char-or-list with a more
+# configurable ignore-eof behaviour.  See zshcontrib.
+
+if [[ -z $BUFFER ]]; then
+  integer eofmax ignoreeof
+  if zstyle -s ":zle:$WIDGET" ignore-eof-count eofmax; then
+    ignoreeof=1
+  else
+    [[ -o ignore_eof ]] && ignoreof=1
+  fi
+  if [[ -n $ignoreeof ]]; then
+    integer -g __eof_count
+
+    if [[ eofmax -le 0 ]]; then
+      __eof_count=0
+    elif [[ $LASTWIDGET = $WIDGET ]]; then
+      if (( ++__eof_count == eofmax )); then
+	exit
+      fi
+    else
+      __eof_count=1
+    fi
+
+    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
+  else
+    exit
+  fi
+fi
+
+zle .$WIDGET
Index: Src/builtin.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/builtin.c,v
retrieving revision 1.126
diff -u -r1.126 builtin.c
--- Src/builtin.c	9 Sep 2004 10:12:47 -0000	1.126
+++ Src/builtin.c	16 Sep 2004 14:43:23 -0000
@@ -3976,7 +3976,7 @@
 
 /* Flag that we should exit the shell as soon as all functions return. */
 /**/
-int
+mod_export int
 exit_pending;
 
 /* break, bye, continue, exit, logout, return -- most of these take   *
Index: Src/init.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/init.c,v
retrieving revision 1.43
diff -u -r1.43 init.c
--- Src/init.c	13 Sep 2004 13:04:55 -0000	1.43
+++ Src/init.c	16 Sep 2004 14:43:24 -0000
@@ -37,7 +37,7 @@
 #include "version.h"
 
 /**/
-mod_export int noexitct = 0;
+int noexitct = 0;
 
 /* buffer for $_ and its length */
 
Index: Src/Zle/zle_main.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/zle_main.c,v
retrieving revision 1.51
diff -u -r1.51 zle_main.c
--- Src/Zle/zle_main.c	13 Sep 2004 13:04:55 -0000	1.51
+++ Src/Zle/zle_main.c	16 Sep 2004 14:43:25 -0000
@@ -680,7 +680,13 @@
     FD_ZERO(&foofd);
 #endif
 
-    while (!done && !errflag) {
+    /*
+     * A widget function may decide to exit the shell.
+     * We never exit directly from functions, to allow
+     * the shell to tidy up, so we have to test for
+     * that explicitly.
+     */
+    while (!done && !errflag && !exit_pending) {
 
 	statusline = NULL;
 	vilinerange = 0;
@@ -688,27 +694,17 @@
 	selectlocalmap(NULL);
 	bindk = getkeycmd();
 	if (bindk) {
-	    if (!ll && isfirstln && lastchar == eofchar) {
+	    if (!ll && isfirstln && !(zlereadflags & ZLRF_IGNOREEOF) &&
+		lastchar == eofchar) {
 		/*
 		 * Slight hack: this relies on getkeycmd returning
 		 * a value for the EOF character.  However,
 		 * undefined-key is fine.  That's necessary because
 		 * otherwise we can't distinguish this case from
 		 * a ^C.
-		 *
-		 * The noxitct test is done in the top-level loop
-		 * if zle is not running.  As we trap EOFs at this
-		 * level inside zle we need to mimic it here.
-		 * If we break, the top-level loop will actually increment
-		 * noexitct an extra time; that doesn't cause any
-		 * problems.
 		 */
-		if (!(zlereadflags & ZLRF_IGNOREEOF) ||
-		    ++noexitct >= 10)
-		{
-		    eofsent = 1;
-		    break;
-		}
+		eofsent = 1;
+		break;
 	    }
 	    if (execzlefunc(bindk, zlenoargs))
 		handlefeep(zlenoargs);
@@ -904,12 +900,14 @@
     } else if((w = func->widget)->flags & (WIDGET_INT|WIDGET_NCOMP)) {
 	int wflags = w->flags;
 
+#if 0
 	if (keybuf[0] == eofchar && !keybuf[1] &&
 	    !ll && isfirstln && (zlereadflags & ZLRF_IGNOREEOF)) {
 	    showmsg((!islogin) ? "zsh: use 'exit' to exit." :
 		    "zsh: use 'logout' to logout.");
 	    ret = 1;
 	} else {
+#endif
 	    if(!(wflags & ZLE_KEEPSUFFIX))
 		removesuffix();
 	    if(!(wflags & ZLE_MENUCMP)) {
@@ -933,7 +931,9 @@
 	    }
 	    if (!(wflags & ZLE_NOTCOMMAND))
 		lastcmd = wflags;
+#if 0
 	}
+#endif
 	r = 1;
     } else {
 	Shfunc shf = (Shfunc) shfunctab->getnode(shfunctab, w->u.fnnam);


-- 
Peter Stephenson <pws@xxxxxxx>                  Software Engineer
CSR Ltd., Science Park, Milton Road,
Cambridge, CB4 0WH, UK                          Tel: +44 (0)1223 692070


**********************************************************************
This email and any files transmitted with it are confidential and
intended solely for the use of the individual or entity to whom they
are addressed. If you have received this email in error please notify
the system manager.

This footnote also confirms that this email message has been swept by
MIMEsweeper for the presence of computer viruses.

www.mimesweeper.com
**********************************************************************



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