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

Re: WORDCHARS, etc.



(I sent this yesterday, but it's still stuck in the mail queue.  The other
version may appear any moment between now and Christmas.)

OK, here's an attempt at passing arguments to widgets.  I've used
Wayne's suggestions (incompatible with what was previously implemented),

} If we're going to start allowing arbitrary arguments to be specified
} then we need some kind of option syntax so we can set either or both
} args for a function.  How about adding the -n# option to set an actual
} value, and the -N option to set the number as unspecified (i.e. "use
} the default").
}
} Alternately, current commands like isearch can be tweaked to look for
} a string arg and only read the keyboard if no string input was
} specified.

To make it transparent between builtin and function widgets, the latter get
passed all the remaining arguments to the zle command as positional
parameters (though there's nothing to stop you calling the function
directly which should have virtually the same effect inside another widget
function), while builtin commands have to look at a new global variable
zleargs.

Only two functions currently use zleargs; we can take suggestions for any
other possibilities, such as the word stuff.

The incremental search commands get a bindkey-like string, i.e. it can have
control characters in it.  This is safe in that any remaining characters
after the isearch finishes are junked, e.g. `zle
history-incremental-search-backwards "foo\nbar\n"' looks back for foo and
accepts the first line it finds, but the "bar\n" has no effect.  Control
returns to the keyboard immediately, i.e. you can edit the buffer if you
didn't stick a control character at the end.  If you want, I could make it
so that the string was always interpreted as literal characters (this would
take some hackery).  Currently, you can't repeat with the same key; I'm not
sure if this is a bug or not but maybe it can be changed.

Also, universal-argument can take a string which will be used to give a
value to the numeric argument.  This is the same as NUMERIC=<num>.

"Bart Schaefer" wrote:
> Which reminds me to again repeat my bug report from 4099:
> 
> zagzig<1> fnord() { zle digit-argument ; BUFFER="$BUFFER $NUMERIC" }
> zagzig<2> zle -N fnord   
> zagzig<3> bindkey '^X^F' fnord
> zagzig<4>  1 6 66 666 6666 66666 666666 6666666 66666666 666666666 -192326792
> 6
> 
> (the last line comes from repeatedly hitting ^X^F).

This was because digit-argument took ^F as the digit typed.  I've made it
feep if the digit isn't between '0' and '9'.  Code like

digarg() { zle digit-argument; }
zle -N digarg
bindkey '^X0' digarg

remains valid.

One problem remains with the $NUMERIC mechanism:  there's no way of
differentiating between the case where the prefix was given as 1 and where
no prefix was given.  This is already noticeable in the completion code for
specifying numbers of correction.  Possibilities are either a separate
parameter, which is clumsy, or altering NUMERIC in some way:  I would
prefer that it is still numerically 1 in either case to avoid confusing
functions, but maybe it could be '+1' if the prefix wasn't set.  That would
mean making it a string instead of an integer parameter.  I haven't done
anything about this yet.

By the way, somebody deleted or caused never to have existed the
documentation for getkeystring(), which I had to work out.

--- Doc/Zsh/mod_zle.yo.zargs	Mon Feb 15 12:11:29 1999
+++ Doc/Zsh/mod_zle.yo	Sun Jun 13 16:19:47 1999
@@ -166,7 +166,7 @@
 xitem(tt(zle) tt(-A) var(old-widget) var(new-widget))
 xitem(tt(zle) tt(-N) var(widget) [ var(function) ])
 xitem(tt(zle) tt(-C) var(widget) var(completion-widget) var(function))
-item(tt(zle) var(widget))(
+item(tt(zle) var(widget) tt([ -n) var(num) tt(]) tt([ -N ]) var(args) ...)(
 The tt(zle) builtin performs a number of different actions concerning
 ZLE.  Which operation it performs depends on its options:
 
@@ -203,9 +203,20 @@
 ifnzman(noderef(Completion Widgets))\
 .
 )
-item(var(widget))(
+item(var(widget) tt([ -n) var(num) tt(]) tt([ -N ]) var(args) ...)(
 Invoke the specified widget.  This can only be done when ZLE is
 active; normally this will be within a user-defined widget.
+
+With the options tt(-n) and tt(-N), the current numerical argument will be
+saved and then restored after the call to tt(widget); `tt(-n) var(num)'
+sets the numerical argument temporarily to var(num), while `tt(-N)' sets it
+to the default, i.e. as if there were none.
+
+Any further arguments will be passed to the widget.  If it is a shell
+function, these are passed down as postional parameters; for builtin
+widgets it is up to the widget in question what it does with them.
+Currently arguments are only handled by the incremental-search commands and
+by tt(universal-argument). 
 )
 enditem()
 )
--- Doc/Zsh/zle.yo.zargs	Sat Jun 12 14:14:05 1999
+++ Doc/Zsh/zle.yo	Sun Jun 13 16:39:22 1999
@@ -414,6 +414,17 @@
 is not bound to one of the above functions, or tt(self-insert) or
 tt(self-insert-unmeta), will have the same effect but the function will be
 executed.
+
+When called from a widget function by the tt(zle) command, the incremental
+search commands can take a string argument.  This will be treated a string
+of keys, as for arguments to the tt(bindkey) command, and used as initial
+input for the command.  Any characters in the string which are unused by
+the incremental search will be silently ignored.  For example,
+
+example(zle history-incremental-search-backward forceps)
+
+will search backwards for tt(forceps), leaving the minibuffer containing
+the string `tt(forceps)'.
 )
 tindex(history-incremental-search-forward)
 item(tt(history-incremental-search-forward) (^S ^Xs) (unbound) (unbound))(
@@ -800,7 +811,11 @@
 tindex(digit-argument)
 item(tt(digit-argument) (ESC-0..ESC-9) (1-9) (unbound))(
 Start a new numeric argument, or add to the current one.
-See also tt(vi-digit-or-beginning-of-line).
+See also tt(vi-digit-or-beginning-of-line).  This only works if bound to a
+key sequence ending in a decimal digit.
+
+Inside a widget function, a call to this function treats the last key of
+the key sequence which called the widget as the digit.
 )
 tindex(neg-argument)
 item(tt(neg-argument) (ESC--) (unbound) (unbound))(
@@ -815,6 +830,10 @@
 twice, followed immediately by tt(forward-char), move forward sixteen
 spaces; if instead it is followed by tt(-2), then tt(forward-char),
 move backward two spaces.
+
+Inside a widget function, if passed an argument, i.e. `tt(zle
+universal-argument) var(num)', the numerical argument will be set to
+var(num); this is equivalent to `tt(NUMERIC=)var(num)'.
 )
 enditem()
 texinode(Completion)(Miscellaneous)(Arguments)(Zsh Line Editor)
--- Src/Zle/zle_hist.c.zargs	Wed Jun  2 09:14:53 1999
+++ Src/Zle/zle_hist.c	Sun Jun 13 16:04:03 1999
@@ -648,7 +648,7 @@
     int sbptr = 0, top_spot = 0, pos, sibuf = 80;
     int nomatch = 0, skip_line = 0, skip_pos = 0;
     int odir = dir, sens = zmult == 1 ? 3 : 1;
-    int hl = histline;
+    int hl = histline, savekeys = -1;
     Thingy cmd;
     char *okeymap = curkeymapname;
     static char *previous_search = NULL;
@@ -657,6 +657,14 @@
 
     clearlist = 1;
 
+    if (*zleargs) {
+	int len;
+	char *arg;
+	savekeys = kungetct;
+	arg = getkeystring(*zleargs, &len, 2, NULL);
+	ungetkeys(arg, len);
+    }
+
     strcpy(ibuf, ISEARCH_PROMPT);
     memcpy(ibuf + NORM_PROMPT_POS, (dir == 1) ? "fwd" : "bck", 3);
     remember_edits();
@@ -863,6 +871,12 @@
     }
     statusline = NULL;
     selectkeymap(okeymap, 1);
+    /*
+     * Don't allow unused characters provided as a string to the
+     * widget to overflow and be used as separated commands.
+     */
+    if (savekeys >= 0 && kungetct > savekeys)
+	kungetct = savekeys;
 }
 
 /**/
--- Src/Zle/zle_main.c.zargs	Mon Jun  7 13:29:36 1999
+++ Src/Zle/zle_main.c	Sun Jun 13 16:02:37 1999
@@ -72,6 +72,11 @@
 /**/
 Widget compwidget;
 
+/* arguments for the current command */
+
+/**/
+char **zleargs;
+
 /* the status line, and its length */
 
 /**/
@@ -111,6 +116,11 @@
 /**/
 int feepflag;
 
+/* Number of characters waiting to be read by the ungetkeys mechanism */
+
+/**/
+int kungetct;
+
 #ifdef FIONREAD
 static int delayzsetterm;
 #endif
@@ -262,7 +272,7 @@
 }
 
 static char *kungetbuf;
-static int kungetct, kungetsz;
+static int kungetsz;
 
 /**/
 void
@@ -540,7 +550,7 @@
 		break;
 	    }
 	    if (bindk) {
-		execzlefunc(bindk);
+		execzlefunc(bindk, NULL);
 		handleprefixes();
 		/* for vi mode, make sure the cursor isn't somewhere illegal */
 		if (invicmdmode() && cs > findbol() &&
@@ -592,11 +602,12 @@
 
 /**/
 void
-execzlefunc(Thingy func)
+execzlefunc(Thingy func, char **argptr)
 {
     int r = 0;
     Widget w;
 
+    DPUTS(useheap, "BUG: heap allocation in execzlefunc");
     if(func->flags & DISABLED) {
 	/* this thingy is not the name of a widget */
 	char *nm = niceztrdup(func->nam);
@@ -607,8 +618,15 @@
 	zsfree(msg);
 	feep();
     } else if((w = func->widget)->flags & (WIDGET_INT|WIDGET_NCOMP)) {
+	/*
+	 * For internal widgets, we pass arguments in the array zleargs.
+	 * These never get modified directly.
+	 */
+	char **oldzleargs = zleargs, *dummyargs[] = { "", NULL};
 	int wflags = w->flags;
 
+	zleargs = argptr ? argptr : dummyargs;
+
 	if(!(wflags & ZLE_KEEPSUFFIX))
 	    removesuffix();
 	if(!(wflags & ZLE_MENUCMP)) {
@@ -627,7 +645,13 @@
 	if (!(wflags & ZLE_NOTCOMMAND))
 	    lastcmd = wflags;
 	r = 1;
+
+	zleargs = oldzleargs;
     } else {
+	/*
+	 * For function widgets, we pass arguments by the usual
+	 * function mechanism.
+	 */
 	List l = getshfunc(w->u.fnnam);
 
 	if(l == &dummy_list) {
@@ -641,11 +665,17 @@
 	    feep();
 	} else {
 	    int osc = sfcontext, osi = movefd(0);
+	    LinkList args;
 
 	    startparamscope();
 	    makezleparams(0);
 	    sfcontext = SFC_WIDGET;
-	    doshfunc(w->u.fnnam, l, NULL, 0, 1);
+	    args = newlinklist();
+	    addlinknode(args, func->nam);
+	    while (*argptr)
+		addlinknode(args, *argptr++);
+	    doshfunc(w->u.fnnam, l, args, 0, 1);
+	    freelinklist(args, (FreeFunc) NULL);
 	    sfcontext = osc;
 	    endparamscope();
 	    lastcmd = 0;
--- Src/Zle/zle_misc.c.zargs	Sun Jun 13 15:28:22 1999
+++ Src/Zle/zle_misc.c	Sun Jun 13 16:46:38 1999
@@ -444,6 +444,11 @@
 {
     int sign = (zmult < 0) ? -1 : 1;
 
+    if (c < '0' || c > '9') {
+	feep();
+	return;
+    }
+
     if (!(zmod.flags & MOD_TMULT))
 	zmod.tmult = 0;
     if (zmod.flags & MOD_NEG) {
@@ -475,6 +480,11 @@
 universalargument(void)
 {
     int digcnt = 0, pref = 0, minus = 1, gotk;
+    if (*zleargs) {
+	zmod.mult = atoi(*zleargs);
+	zmod.flags |= MOD_MULT;
+	return;
+    }
     while ((gotk = getkey(0)) != EOF) {
 	if (gotk == '-' && !digcnt) {
 	    minus = -1;
--- Src/Zle/zle_thingy.c.zargs	Tue May 11 11:20:53 1999
+++ Src/Zle/zle_thingy.c	Sun Jun 13 14:43:01 1999
@@ -357,10 +357,6 @@
 
     /* check number of arguments */
     for(n = 0; args[n]; n++) ;
-    if(!op->o && n != 1 && n != 2) {
-	zerrnam(name, "wrong number of arguments", NULL, 0);
-	return 1;
-    }
     if(n < op->min) {
 	zerrnam(name, "not enough arguments for -%c", NULL, op->o);
 	return 1;
@@ -517,29 +513,61 @@
 {
     Thingy t;
     struct modifier modsave;
+    int saveflag = 0;
 
     if(!zleactive || incompctlfunc || incompfunc) {
 	zerrnam(name, "widgets can only be called when ZLE is active",
 	    NULL, 0);
 	return 1;
     }
-    if (args[1]) {
-	modsave = zmod;
-	if (isdigit(*args[1])) {
-	    zmod.mult = atoi(args[1]);
-	    zmod.flags |= MOD_MULT;
+
+    while (*args && **args == '-') {
+	char *num;
+	if (!args[0][1] || args[0][1] == '-') {
+	    args++;
+	    break;
 	}
-	else {
-	    zmod.mult = 1;
-	    zmod.flags &= ~MOD_MULT;
+	while (*++(*args)) {
+	    switch (**args) {
+	    case 'n':
+		num = args[0][1] ? args[0]+1 : args[1];
+		if (!num) {
+		    zwarnnam(name, "number expected after -%c", NULL, **args);
+		    return 1;
+		}
+		if (!args[0][1])
+		    args++;
+		modsave = zmod;
+		saveflag = 1;
+		zmod.mult = atoi(num);
+		zmod.flags |= MOD_MULT;
+		break;
+	    case 'N':
+		modsave = zmod;
+		saveflag = 1;
+		zmod.mult = 1;
+		zmod.flags &= ~MOD_MULT;
+		break;
+	    default:
+		zwarnnam(name, "unknown option: %s", *args, 0);
+		return 1;
+	    }
 	}
+	args++;
     }
-    t = rthingy(args[0]);
+    if (!args[0]) {
+	zwarnnam(name, "wrong number of arguments", NULL, 0);
+	if (saveflag)
+	    zmod = modsave;
+	return 1;
+    }
+
+    t = rthingy(*args++);
     PERMALLOC {
-      execzlefunc(t);
+      execzlefunc(t, args);
     } LASTALLOC;
     unrefthingy(t);
-    if (args[1])
+    if (saveflag)
 	zmod = modsave;
     return 0;
 }
--- Src/Zle/zle_vi.c.zargs	Wed Mar 17 09:37:43 1999
+++ Src/Zle/zle_vi.c	Sun Jun 13 14:06:57 1999
@@ -175,7 +175,7 @@
 	    /* The command key is repeated: a number of lines is used. */
 	    dovilinerange();
 	else
-	    execzlefunc(k2);
+	    execzlefunc(k2, NULL);
 	if(vichgrepeat)
 	    zmult = mult1;
 	else
--- Src/utils.c.zargs	Thu Jun 10 16:38:50 1999
+++ Src/utils.c	Sun Jun 13 15:15:59 1999
@@ -3080,6 +3080,22 @@
 }
 #endif
 
+/*
+ * Decode a key string, turning it into the literal characters.
+ * The length is returned in len.
+ * fromwhere determines how the processing works.
+ *   0:  Don't handle keystring, just print-like escapes.
+ *       Expects misc to be present.
+ *   1:  Handle Emacs-like \C-X arguments etc., but not ^X
+ *       Expects misc to be present.
+ *   2:  Handle ^X as well as emacs-like keys; don't handle \c
+ *       for no newlines.
+ *   3:  As 1, but don't handle \c.
+ *   4:  Do $'...' quoting.  Overwrites the existing string instead of
+ *       zhalloc'ing 
+ *   5:  As 2, but \- is special.  Expects misc to be defined.
+ */
+
 /**/
 char *
 getkeystring(char *s, int *len, int fromwhere, int *misc)


-- 
Peter Stephenson <pws@xxxxxxxxxxxxxxxxx>       Tel: +39 050 844536
WWW:  http://www.ifh.de/~pws/
Dipartimento di Fisica, Via Buonarroti 2, 56127 Pisa, Italy



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