I've attached draft versions of the incremental search tests, based on the suggestions of Bart and Peter. I just added on Peter's latest change, previously I was using a hard coded escape sequence. The zletest file is based on comptest, and includes debugging code. The test is flaky, so there might be some buffering issues, or I'm not properly reseting the state between tests. (Or just confused on what to expect...) If you are interested in seeing what it does, you can add these under the Test directory and run: make TESTNUM=X check I would be interest in any feedback. These are still draft condition, but might be of interest to anyone following this thread. -FR On Wed, Jan 4, 2012 at 9:38 AM, Peter Stephenson <p.w.stephenson@xxxxxxxxxxxx> wrote: > On Wed, 21 Dec 2011 11:39:47 +0000 > Peter Stephenson <Peter.Stephenson@xxxxxxx> wrote: >> Probably easier is to intercept the terminal output at a low-level >> inside the shell by having an option that directly outputs values from >> an associative array with termcap codes as keys (this doesn't need to be >> particularly user-friendly, and as zsh internally still uses termcap >> codes this looks like the easiest way to test it) instead of using the >> termcap output functions. That shouldn't be too much work --- termcap >> is vastly simpler than e.g. curses --- and makes the job no harder (!) >> than testing completion. There are also potential uses for this in >> debugging --- it should provide a simpler method of finding out what has >> caused the cursor to end up where it did. > > A function both makes this flexible and allows you to handle all termcap > entries uniformly. > > I've done this by adding a generic command for zle transformations, but > I don't know that we'll ever use this for anything else. > > Try > > tcfunc() { > if [[ -n $2 ]]; then > REPLY="<tc=$1,arg=$2>" > else > REPLY="<tc=$1>" > fi > } > zle -T tc tcfunc > > and > > zle -Tr tc > > to turn it off (your typing had better be accurate). > > There's a completely irrelevant zsfree(argzero) snuck in because I was > too lazy to separate it. This stops a valgrind warning in some cases > (it's a very minor leak since it only happens once at the start). > > Index: Doc/Zsh/zle.yo > =================================================================== > RCS file: /cvsroot/zsh/zsh/Doc/Zsh/zle.yo,v > retrieving revision 1.95 > diff -p -u -r1.95 zle.yo > --- Doc/Zsh/zle.yo 4 Nov 2011 14:14:27 -0000 1.95 > +++ Doc/Zsh/zle.yo 4 Jan 2012 17:32:13 -0000 > @@ -370,6 +370,7 @@ 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(-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) ...)( > The tt(zle) builtin performs a number of different actions concerning > ZLE. > @@ -572,6 +573,33 @@ this may have been by a previous call to > notification. To test if a zle widget may be called at this point, execute > tt(zle) with no arguments and examine the return status. > ) > +item(tt(-T))( > +This is used to add, list or remove internal transformations on the > +processing performed by the line editor. It is typically used only for > +debugging or testing and is therefore of little interest to the general > +user. > + > +`tt(zle -T) var(transformation) var(func)' specifies that the > +given var(transformation) (see below) is effected by shell function > +var(func). > + > +`tt(zle -Tr) var(transformation)' removes the given var(transformation) > +if it was present (it is not an error if none was). > + > +`tt(zle -TL)' can be used to list all transformations currently in > +operation. > + > +Currently the only transformation is tt(tc). This is used instead > +of outputting termcap codes to the terminal. When the transformation is > +in operation the shell function is passed the termcap code that would be > +output as its first argument; if the operation required a numeric > +argument, that is passed as a second argument. The function should set > +the shell variable tt(REPLY) to the transformed termcap code. Typically > +this is used to produce some simply formatted version of the code and > +optional argument for debugging or testing. Note that this > +transformation is not applied to other non-printing characters such as > +carriage returns and newlines. > +) > item(var(widget) tt([ -n) var(num) tt(]) tt([ -Nw ] [ -K) var(keymap) tt(]) var(args) ...)( > Invoke the specified widget. This can only be done when ZLE is > active; normally this will be within a user-defined widget. > Index: Src/init.c > =================================================================== > RCS file: /cvsroot/zsh/zsh/Src/init.c,v > retrieving revision 1.120 > diff -p -u -r1.120 init.c > --- Src/init.c 9 May 2011 09:49:09 -0000 1.120 > +++ Src/init.c 4 Jan 2012 17:32:14 -0000 > @@ -558,6 +558,19 @@ static char *tccapnams[TC_COUNT] = { > "ku", "kd", "kl", "kr", "sc", "rc", "bc", "AF", "AB" > }; > > +/**/ > +mod_export char * > +tccap_get_name(int cap) > +{ > + if (cap >= TC_COUNT) { > +#ifdef DEBUG > + dputs("name of invalid capability %d requested", cap); > +#endif > + return ""; > + } > + return tccapnams[cap]; > +} > + > /* Initialise termcap */ > > /**/ > @@ -978,6 +991,7 @@ setupshin(char *runscript) > exit(127); > } > scriptfilename = sfname; > + zsfree(argzero); /* ztrdup'd in parseargs */ > argzero = runscript; > } > /* > Index: Src/Zle/zle_main.c > =================================================================== > RCS file: /cvsroot/zsh/zsh/Src/Zle/zle_main.c,v > retrieving revision 1.131 > diff -p -u -r1.131 zle_main.c > --- Src/Zle/zle_main.c 2 Jan 2012 19:31:16 -0000 1.131 > +++ Src/Zle/zle_main.c 4 Jan 2012 17:32:14 -0000 > @@ -1927,7 +1927,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, "aAcehM:m:p:r:t:", NULL), > - BUILTIN("zle", 0, bin_zle, 0, -1, 0, "aAcCDFgGIKlLmMNRU", NULL), > + BUILTIN("zle", 0, bin_zle, 0, -1, 0, "aAcCDFgGIKlLmMNrRTU", NULL), > }; > > /* The order of the entries in this table has to match the *HOOK > Index: Src/Zle/zle_refresh.c > =================================================================== > RCS file: /cvsroot/zsh/zsh/Src/Zle/zle_refresh.c,v > retrieving revision 1.88 > diff -p -u -r1.88 zle_refresh.c > --- Src/Zle/zle_refresh.c 17 Aug 2011 10:15:50 -0000 1.88 > +++ Src/Zle/zle_refresh.c 4 Jan 2012 17:32:14 -0000 > @@ -233,6 +233,12 @@ int n_region_highlights; > /**/ > int region_active; > > +/* > + * Name of function to use to output termcap values, if defined. > + */ > +/**/ > +char *tcout_func_name; > + > #ifdef HAVE_SELECT > /* cost of last update */ > /**/ > @@ -2271,11 +2277,78 @@ tc_downcurs(int ct) > return ret; > } > > +/* > + * Output a termcap value using a function defined by "zle -T tc". > + * Loosely inspired by subst_string_by_func(). > + * > + * cap is the internal index for the capability; it will be looked up > + * in the table and the string passed to the function. > + * > + * arg is eithr an argument to the capability or -1 if there is none; > + * if it is not -1 it will be passed as an additional argument to the > + * function. > + * > + * outc is the output function; currently this is always putshout > + * but in principle it may be used to output to a string. > + */ > + > +/**/ > +static void > +tcout_via_func(int cap, int arg, int (*outc)(int)) > +{ > + Shfunc tcout_func; > + int osc, osm, old_incompfunc; > + > + osc = sfcontext; > + osm = stopmsg; > + old_incompfunc = incompfunc; > + > + sfcontext = SFC_SUBST; > + incompfunc = 0; > + > + if ((tcout_func = getshfunc(tcout_func_name))) { > + LinkList l = newlinklist(); > + char buf[DIGBUFSIZE], *str; > + > + addlinknode(l, tcout_func_name); > + addlinknode(l, tccap_get_name(cap)); > + > + if (arg != -1) { > + sprintf(buf, "%d", arg); > + addlinknode(l, buf); > + } > + > + (void)doshfunc(tcout_func, l, 1); > + > + str = getsparam("REPLY"); > + if (str) { > + while (*str) { > + int chr; > + if (*str == Meta) { > + chr = str[1] ^ 32; > + str += 2; > + } else { > + chr = *str++; > + } > + (void)outc(chr); > + } > + } > + } > + > + sfcontext = osc; > + stopmsg = osm; > + incompfunc = old_incompfunc; > +} > + > /**/ > mod_export void > tcout(int cap) > { > - tputs(tcstr[cap], 1, putshout); > + if (tcout_func_name) { > + tcout_via_func(cap, -1, putshout); > + } else { > + tputs(tcstr[cap], 1, putshout); > + } > SELECT_ADD_COST(tclen[cap]); > } > > @@ -2286,7 +2359,11 @@ tcoutarg(int cap, int arg) > char *result; > > result = tgoto(tcstr[cap], arg, arg); > - tputs(result, 1, putshout); > + if (tcout_func_name) { > + tcout_via_func(cap, arg, putshout); > + } else { > + tputs(result, 1, putshout); > + } > SELECT_ADD_COST(strlen(result)); > } > > Index: Src/Zle/zle_thingy.c > =================================================================== > RCS file: /cvsroot/zsh/zsh/Src/Zle/zle_thingy.c,v > retrieving revision 1.35 > diff -p -u -r1.35 zle_thingy.c > --- Src/Zle/zle_thingy.c 4 Nov 2011 14:14:27 -0000 1.35 > +++ Src/Zle/zle_thingy.c 4 Jan 2012 17:32:14 -0000 > @@ -353,6 +353,7 @@ bin_zle(char *name, char **args, Options > { 'K', bin_zle_keymap, 1, 1 }, > { 'I', bin_zle_invalidate, 0, 0 }, > { 'F', bin_zle_fd, 0, 2 }, > + { 'T', bin_zle_transform, 0, 2}, > { 0, bin_zle_call, 0, -1 }, > }; > struct opn const *op, *opp; > @@ -856,6 +857,69 @@ bin_zle_fd(char *name, char **args, Opti > return 0; > } > > +/**/ > +static int > +bin_zle_transform(char *name, char **args, Options ops, UNUSED(char func)) > +{ > + /* > + * -1: too few arguments > + * 0: just right > + * 1: too many arguments > + * 2: first argument not recognised > + */ > + int badargs = 0; > + > + if (OPT_ISSET(ops,'L')) { > + if (args[0]) { > + if (args[1]) { > + badargs = 1; > + } else if (strcmp(args[0], "tc")) { > + badargs = 2; > + } > + } > + if (!badargs && tcout_func_name) { > + fputs("zle -T tc ", stdout); > + quotedzputs(tcout_func_name, stdout); > + putchar('\n'); > + } > + } else if (OPT_ISSET(ops,'r')) { > + if (!args[0]) { > + badargs = -1; > + } else if (args[1]) { > + badargs = 1; > + } else if (tcout_func_name) { > + zsfree(tcout_func_name); > + tcout_func_name = NULL; > + } > + } else { > + if (!args[0] || !args[1]) { > + badargs = -1; > + /* we've already checked args <= 2 */ > + } else { > + if (!strcmp(args[0], "tc")) { > + if (tcout_func_name) { > + zsfree(tcout_func_name); > + } > + tcout_func_name = ztrdup(args[1]); > + } else { > + badargs = 2; > + } > + } > + } > + > + if (badargs) { > + if (badargs == 2) { > + zwarnnam(name, "-T: no such transformation '%s'", args[0]); > + } else { > + char *way = (badargs > 0) ? "many" : "few"; > + zwarnnam(name, "too %s arguments for option -T", way); > + } > + return 1; > + } > + > + return 0; > +} > + > /*******************/ > /* initialiasation */ > /*******************/
Attachment:
X01isearch.ztst
Description: Binary data
Attachment:
zletest
Description: Binary data