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

[PATCH] User-defined widgets can continue past push-line-or-edit



This one is going to need some real-life testing.

Before the appended patch, either "zle push-line-or-edit" had to be
last thing done by any user-defined widget, or it had to be
special-cased for PREBUFFER because at the PS2 prompt it effectively
executed a send-break to force the parser to return to the PS1 prompt.

With this patch, the current user-defined widget may continue
executing through to either normal return or until another widget that
ends the ZLE session (such as accept-line) is called.  However, this
is not transitive, that is, if user-defined widget X uses "zle Y" and
Y is a user-defined widget that calls push-line-or-edit, then X will
stop immediately after Y returns.  It may be possible to change that,
but: one thing at a time.

Although push-line-or-edit clears the current BUFFER, the
already-parsed PREBUFFER won't be discarded (from the parser state)
until ZLE finishes.  This means that if a widget such as accept-line
is called in this circumstance (e.g., at PS2 prompt) the entire parser
state up to that point is accepted.  This has the probably-unwanted
effect of restarting the parser at the end of "$PREBUFFER$BUFFFER"
instead of at PS1, thereby potentially duplicating what was just
pushed (with anything new in BUFFER in between).  Of course, you can
stuff something into BUFFER that finishes the expression represented
by PREBUFFER, which will then execute that and restart with the pushed
state.

The foregoing all applies to "zle push-input" which is implemented by
call to pushlineoredit().
diff --git a/Src/Zle/zle_hist.c b/Src/Zle/zle_hist.c
index 0fdad70d9..38f2e0fcc 100644
--- a/Src/Zle/zle_hist.c
+++ b/Src/Zle/zle_hist.c
@@ -871,8 +871,11 @@ pushlineoredit(char **args)
     }
     ret = pushline(args);
     if (!isfirstln) {
-	errflag |= ERRFLAG_ERROR|ERRFLAG_INT;
-	done = 1;
+	if (sfcontext != SFC_WIDGET) {
+	    errflag |= ERRFLAG_EDIT;
+	    done = 1;
+	} else
+	    done = 2;
     }
     clearlist = 1;
     return ret;
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index 1afb1bf58..69008bbbd 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -1532,6 +1532,10 @@ execzlefunc(Thingy func, char **args, int set_bindk, int set_lbindk)
 	    sfcontext = SFC_WIDGET;
 	    opts[XTRACE] = 0;
 	    ret = doshfunc(shf, largs, 1);
+	    if (done == 2) {
+		errflag |= ERRFLAG_EDIT;
+		done = 1;
+	    }
 	    opts[XTRACE] = oxt;
 	    sfcontext = osc;
 	    endparamscope();
diff --git a/Src/input.c b/Src/input.c
index 8d7f44d7c..cfff586e3 100644
--- a/Src/input.c
+++ b/Src/input.c
@@ -430,7 +430,8 @@ inputline(void)
     }
     if (errflag) {
 	free(ingetcline);
-	errflag |= ERRFLAG_ERROR;
+	if (errflag != ERRFLAG_EDIT)
+	    errflag |= ERRFLAG_ERROR;
 	return lexstop = 1;
     }
     if (isset(VERBOSE)) {
diff --git a/Src/zsh.h b/Src/zsh.h
index a0243e98e..09e656d99 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -2977,7 +2977,11 @@ enum errflag_bits {
      * have exited.  This is reset by "errflag = 0" in
      * loop(toplevel = 1, ...).
      */
-    ERRFLAG_HARD = 4
+    ERRFLAG_HARD = 4,
+    /*
+     * Editing error.  Like user interrupt, but less violent.
+     */
+    ERRFLAG_EDIT = 8
 };
 
 /***********/


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