From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 26992 invoked from network); 14 Jun 1999 07:44:45 -0000 Received: from sunsite.auc.dk (130.225.51.30) by ns1.primenet.com.au with SMTP; 14 Jun 1999 07:44:45 -0000 Received: (qmail 28069 invoked by alias); 14 Jun 1999 07:44:28 -0000 Mailing-List: contact zsh-workers-help@sunsite.auc.dk; run by ezmlm Precedence: bulk X-No-Archive: yes X-Seq: 6609 Received: (qmail 28058 invoked from network); 14 Jun 1999 07:44:26 -0000 Message-Id: <9906140715.AA27470@ibmth.df.unipi.it> To: zsh-workers@sunsite.auc.dk (Zsh hackers list) Subject: Re: WORDCHARS, etc. In-Reply-To: ""Bart Schaefer""'s message of "Sun, 13 Jun 1999 11:17:20 DFT." <990613111720.ZM14111@candle.brasslantern.com> Date: Mon, 14 Jun 1999 09:15:47 +0200 From: Peter Stephenson (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=. "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 Tel: +39 050 844536 WWW: http://www.ifh.de/~pws/ Dipartimento di Fisica, Via Buonarroti 2, 56127 Pisa, Italy