about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Stephenson <pws@zsh.org>2013-11-07 15:19:07 +0000
committerPeter Stephenson <pws@zsh.org>2013-11-07 15:19:07 +0000
commitf77a7a5b18f0650d32e5e8dac1f1cb284a9e4690 (patch)
tree2cfeba444292386f17afa88237ceeaf20c1fdf67
parent375115c7dfd6dff576915d25fe2ecdd381dd9d81 (diff)
downloadzsh-f77a7a5b18f0650d32e5e8dac1f1cb284a9e4690.tar.gz
zsh-f77a7a5b18f0650d32e5e8dac1f1cb284a9e4690.tar.xz
zsh-f77a7a5b18f0650d32e5e8dac1f1cb284a9e4690.zip
31937: zle -Fw uses widget semantics for file descriptor handler
-rw-r--r--ChangeLog7
-rw-r--r--Doc/Zsh/zle.yo11
-rw-r--r--Src/Zle/zle_main.c38
-rw-r--r--Src/Zle/zle_thingy.c16
-rw-r--r--Src/Zle/zle_utils.c7
-rw-r--r--Src/math.c23
-rw-r--r--Test/C01arith.ztst4
7 files changed, 79 insertions, 27 deletions
diff --git a/ChangeLog b/ChangeLog
index 5f5dc719c..2adf991f3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2013-11-07  Peter Stephenson  <p.stephenson@samsung.com>
+
+	* 31937: Doc/Zsh/zle.yo, Src/Zle/zle_main.c,
+	Src/Zle/zle_thingy.c, Src/Zle/zle_utils.c, Src/math.c,
+	Test/C01arith.ztst: zle -Fw uses widget semantics for
+	file descriptor handler.
+
 2013-11-06  Peter Stephenson  <p.w.stephenson@ntlworld.com>
 
 	* unposted: Completion/Debian/Command/.distfiles,
diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo
index 614924bfb..2d7756859 100644
--- a/Doc/Zsh/zle.yo
+++ b/Doc/Zsh/zle.yo
@@ -373,7 +373,7 @@ xitem(tt(zle) tt(-R) [ tt(-c) ] [ var(display-string) ] [ var(string) ... ])
 xitem(tt(zle) tt(-M) var(string))
 xitem(tt(zle) tt(-U) var(string))
 xitem(tt(zle) tt(-K) var(keymap))
-xitem(tt(zle) tt(-F) [ tt(-L) ] [ var(fd) [ var(handler) ] ])
+xitem(tt(zle) tt(-F) [ tt(-L) | tt(-w) ] [ var(fd) [ var(handler) ] ])
 xitem(tt(zle) tt(-I))
 xitem(tt(zle) tt(-T) [ tt(tc) var(function) | tt(-r) tt(tc) | tt(-L) ] )
 item(tt(zle) var(widget) tt([ -n) var(num) tt(]) tt([ -Nw ] [ -K) var(keymap) tt(]) var(args) ...)(
@@ -487,7 +487,7 @@ This keymap selection affects the interpretation of following keystrokes
 within this invocation of ZLE.  Any following invocation (e.g., the next
 command line) will start as usual with the `tt(main)' keymap selected.
 )
-item(tt(-F) [ tt(-L) ] [ var(fd) [ var(handler) ] ])(
+item(tt(-F) [ tt(-L) | tt(-w) ] [ var(fd) [ var(handler) ] ])(
 Only available if your system supports one of the `poll' or `select' system
 calls; most modern systems do.
 
@@ -502,6 +502,13 @@ Note that zle makes no attempt to check whether this fd is actually
 readable when installing the handler.  The user must make their own
 arrangements for handling the file descriptor when zle is not active.
 
+If the option tt(-w) is also given, the var(handler) is instead a
+line editor widget, typically a shell function made into a widget using
+tt(zle -N).  In that case var(handler) can use all the facilities of
+zle to update the current editing line.  Note, however, that as handling
+var(fd) takes place at a low level changes to the display will not
+automatically appear; the widget should call tt(zle -R) to force redisplay.
+
 Any number of handlers for any number of readable file descriptors may be
 installed.  Installing a handler for an var(fd) which is already handled
 causes the existing handler to be replaced.
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index 5798e74b4..6822230b4 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -201,6 +201,8 @@ int nwatch;		/* Number of fd's we are watching */
 int *watch_fds;		/* The list of fds, not terminated! */
 /**/
 char **watch_funcs;	/* The corresponding functions to call, normal array */
+/**/
+int *watch_widgets;     /* 1 if corresponding function is called as widget */
 
 /* set up terminal */
 
@@ -725,7 +727,9 @@ raw_getbyte(long do_keytmout, char *cptr)
 		int lnwatch = nwatch;
 		int *lwatch_fds = zalloc(lnwatch*sizeof(int));
 		char **lwatch_funcs = zarrdup(watch_funcs);
+		int *lwatch_widgets = zalloc(lnwatch*sizeof(int));
 		memcpy(lwatch_fds, watch_fds, lnwatch*sizeof(int));
+		memcpy(lwatch_widgets, watch_widgets, lnwatch*sizeof(int));
 		for (i = 0; i < lnwatch; i++) {
 		    if (
 # ifdef HAVE_POLL
@@ -735,30 +739,37 @@ raw_getbyte(long do_keytmout, char *cptr)
 # endif
 			) {
 			/* Handle the fd. */
-			LinkList funcargs = znewlinklist();
-			zaddlinknode(funcargs, ztrdup(lwatch_funcs[i]));
+			char *fdbuf;
 			{
 			    char buf[BDIGBUFSIZE];
 			    convbase(buf, lwatch_fds[i], 10);
-			    zaddlinknode(funcargs, ztrdup(buf));
+			    fdbuf = ztrdup(buf);
 			}
+
+			if (lwatch_widgets[i]) {
+			    zlecallhook(lwatch_funcs[i], fdbuf);
+			    zsfree(fdbuf);
+			} else {
+			    LinkList funcargs = znewlinklist();
+			    zaddlinknode(funcargs, ztrdup(lwatch_funcs[i]));
+			    zaddlinknode(funcargs, fdbuf);
 # ifdef HAVE_POLL
 #  ifdef POLLERR
-			if (fds[i+1].revents & POLLERR)
-			    zaddlinknode(funcargs, ztrdup("err"));
+			    if (fds[i+1].revents & POLLERR)
+				zaddlinknode(funcargs, ztrdup("err"));
 #  endif
 #  ifdef POLLHUP
-			if (fds[i+1].revents & POLLHUP)
-			    zaddlinknode(funcargs, ztrdup("hup"));
+			    if (fds[i+1].revents & POLLHUP)
+				zaddlinknode(funcargs, ztrdup("hup"));
 #  endif
 #  ifdef POLLNVAL
-			if (fds[i+1].revents & POLLNVAL)
-			    zaddlinknode(funcargs, ztrdup("nval"));
+			    if (fds[i+1].revents & POLLNVAL)
+				zaddlinknode(funcargs, ztrdup("nval"));
 #  endif
 # endif
-
-
-			callhookfunc(lwatch_funcs[i], funcargs, 0, NULL);
+			    callhookfunc(lwatch_funcs[i], funcargs, 0, NULL);
+			    freelinklist(funcargs, freestr);
+			}
 			if (errflag) {
 			    /* No sensible way of handling errors here */
 			    errflag = 0;
@@ -768,7 +779,6 @@ raw_getbyte(long do_keytmout, char *cptr)
 			     */
 			    errtry = 1;
 			}
-			freelinklist(funcargs, freestr);
 		    }
 		}
 		/* Function may have invalidated the display. */
@@ -1960,7 +1970,7 @@ zle_main_entry(int cmd, va_list ap)
 static struct builtin bintab[] = {
     BUILTIN("bindkey", 0, bin_bindkey, 0, -1, 0, "evaM:ldDANmrsLRp", NULL),
     BUILTIN("vared",   0, bin_vared,   1,  1, 0, "aAcef:hi:M:m:p:r:t:", NULL),
-    BUILTIN("zle",     0, bin_zle,     0, -1, 0, "aAcCDFgGIKlLmMNrRTU", NULL),
+    BUILTIN("zle",     0, bin_zle,     0, -1, 0, "aAcCDFgGIKlLmMNrRTUw", NULL),
 };
 
 /* The order of the entries in this table has to match the *HOOK
diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c
index 49d715e06..78c7918d2 100644
--- a/Src/Zle/zle_thingy.c
+++ b/Src/Zle/zle_thingy.c
@@ -781,7 +781,8 @@ bin_zle_fd(char *name, char **args, Options ops, UNUSED(char func))
 	    if (*args && watch_fds[i] != fd)
 		continue;
 	    found = 1;
-	    printf("%s -F %d %s\n", name, watch_fds[i], watch_funcs[i]);
+	    printf("%s -F %s%d %s\n", name, watch_widgets[i] ? "-w " : "",
+		   watch_fds[i], watch_funcs[i]);
 	}
 	/* only return status 1 if fd given and not found */
 	return *args && !found;
@@ -795,6 +796,7 @@ bin_zle_fd(char *name, char **args, Options ops, UNUSED(char func))
 		if (watch_fds[i] == fd) {
 		    zsfree(watch_funcs[i]);
 		    watch_funcs[i] = funcnam;
+		    watch_widgets[i] = OPT_ISSET(ops,'w') ? 1 : 0;
 		    found = 1;
 		    break;
 		}
@@ -807,9 +809,12 @@ bin_zle_fd(char *name, char **args, Options ops, UNUSED(char func))
 					newnwatch * sizeof(int));
 	    watch_funcs = (char **)zrealloc(watch_funcs,
 					    (newnwatch+1) * sizeof(char *));
+	    watch_widgets = (int *)zrealloc(watch_widgets,
+					    newnwatch * sizeof(int));
 	    watch_fds[nwatch] = fd;
 	    watch_funcs[nwatch] = funcnam;
 	    watch_funcs[newnwatch] = NULL;
+	    watch_widgets[nwatch] = OPT_ISSET(ops,'w') ? 1 : 0;
 	    nwatch = newnwatch;
 	}
     } else {
@@ -817,32 +822,39 @@ bin_zle_fd(char *name, char **args, Options ops, UNUSED(char func))
 	for (i = 0; i < nwatch; i++) {
 	    if (watch_fds[i] == fd) {
 		int newnwatch = nwatch-1;
-		int *new_fds;
+		int *new_fds, *new_widgets;
 		char **new_funcs;
 
 		zsfree(watch_funcs[i]);
 		if (newnwatch) {
 		    new_fds = zalloc(newnwatch*sizeof(int));
 		    new_funcs = zalloc((newnwatch+1)*sizeof(char*));
+		    new_widgets = zalloc(newnwatch*sizeof(int));
 		    if (i) {
 			memcpy(new_fds, watch_fds, i*sizeof(int));
 			memcpy(new_funcs, watch_funcs, i*sizeof(char *));
+			memcpy(new_widgets, watch_widgets, i*sizeof(int));
 		    }
 		    if (i < newnwatch) {
 			memcpy(new_fds+i, watch_fds+i+1,
 			       (newnwatch-i)*sizeof(int));
 			memcpy(new_funcs+i, watch_funcs+i+1,
 			       (newnwatch-i)*sizeof(char *));
+			memcpy(new_widgets+i, watch_widgets+i+1,
+			       (newnwatch-i)*sizeof(int));
 		    }
 		    new_funcs[newnwatch] = NULL;
 		} else {
 		    new_fds = NULL;
 		    new_funcs = NULL;
+		    new_widgets = NULL;
 		}
 		zfree(watch_fds, nwatch*sizeof(int));
 		zfree(watch_funcs, (nwatch+1)*sizeof(char *));
+		zfree(watch_widgets, nwatch*sizeof(int));
 		watch_fds = new_fds;
 		watch_funcs = new_funcs;
+		watch_widgets = new_widgets;
 		nwatch = newnwatch;
 		found = 1;
 		break;
diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c
index b84d253bb..b82e54ce5 100644
--- a/Src/Zle/zle_utils.c
+++ b/Src/Zle/zle_utils.c
@@ -1643,7 +1643,7 @@ zlecallhook(char *name, char *arg)
 {
     Thingy thingy = rthingy_nocreate(name);
     int saverrflag, savretflag;
-    char *args[3];
+    char *args[2];
 
     if (!thingy)
 	return;
@@ -1651,9 +1651,8 @@ zlecallhook(char *name, char *arg)
     saverrflag = errflag;
     savretflag = retflag;
 
-    args[0] = thingy->nam;
-    args[1] = arg;
-    args[2] = NULL;
+    args[0] = arg;
+    args[1] = NULL;
     execzlefunc(thingy, args, 1);
     unrefthingy(thingy);
 
diff --git a/Src/math.c b/Src/math.c
index eae283d19..b21a3adee 100644
--- a/Src/math.c
+++ b/Src/math.c
@@ -1374,6 +1374,19 @@ mathevalarg(char *s, char **ss)
     mnumber x;
     int xmtok = mtok;
 
+    /*
+     * At this entry point we don't allow an empty expression,
+     * whereas we do with matheval().  I'm not sure if this
+     * difference is deliberate, but it does mean that e.g.
+     * $array[$ind] where ind hasn't been set produces an error,
+     * which is probably safe.
+     *
+     * To avoid a more opaque error further in, bail out here.
+     */
+    if (!*s) {
+	zerr("bad math expression: empty string");
+	return (zlong)0;
+    }
     x = mathevall(s, MPREC_ARG, ss);
     if (mtok == COMMA)
 	(*ss)--;
@@ -1401,6 +1414,7 @@ checkunary(int mtokc, char *mptr)
     }
     if (errmsg) {
 	int len, over = 0;
+	char *errtype = errmsg == 2 ? "operator" : "operand";
 	while (inblank(*mptr))
 	    mptr++;
 	len = ztrlen(mptr);
@@ -1408,9 +1422,12 @@ checkunary(int mtokc, char *mptr)
 	    len = 10;
 	    over = 1;
 	}
-	zerr("bad math expression: %s expected at `%l%s'",
-	     errmsg == 2 ? "operator" : "operand",
-	     mptr, len, over ? "..." : "");
+	if (!*mptr)
+	    zerr("bad math expression: %s expected at end of string",
+		errtype);
+	else
+	    zerr("bad math expression: %s expected at `%l%s'",
+		 errtype, mptr, len, over ? "..." : "");
     }
     unary = !(tp & OP_OPF);
 }
diff --git a/Test/C01arith.ztst b/Test/C01arith.ztst
index 71c8a1969..c19135ce6 100644
--- a/Test/C01arith.ztst
+++ b/Test/C01arith.ztst
@@ -134,11 +134,11 @@
 
   print $(( a = ))
 1:empty assignment
-?(eval):1: bad math expression: operand expected at `'
+?(eval):1: bad math expression: operand expected at end of string
 
   print $(( 3, ))
 1:empty right hand of comma
-?(eval):1: bad math expression: operand expected at `'
+?(eval):1: bad math expression: operand expected at end of string
 
   print $(( 3,,4 ))
 1:empty middle of comma