From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 8552 invoked by alias); 4 Jan 2012 17:38:56 -0000 Mailing-List: contact zsh-workers-help@zsh.org; run by ezmlm Precedence: bulk X-No-Archive: yes List-Id: Zsh Workers List List-Post: List-Help: X-Seq: 30084 Received: (qmail 23640 invoked from network); 4 Jan 2012 17:38:53 -0000 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on f.primenet.com.au X-Spam-Level: X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_LOW autolearn=ham version=3.3.2 Received-SPF: neutral (ns1.primenet.com.au: 74.125.82.171 is neither permitted nor denied by SPF record at ntlworld.com) X-ProxyUser-IP: 86.6.29.42 Date: Wed, 4 Jan 2012 17:38:44 +0000 From: Peter Stephenson To: Subject: Re: Adding tests for zle? The missing X series tests Message-ID: <20120104173844.34681459@pws-pc.ntlworld.com> In-Reply-To: <20111221113947.75942dd8@pwslap01u.europe.root.pri> References: <20111221113947.75942dd8@pwslap01u.europe.root.pri> X-Mailer: Claws Mail 3.7.9 (GTK+ 2.24.7; x86_64-redhat-linux-gnu) Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit On Wed, 21 Dec 2011 11:39:47 +0000 Peter Stephenson 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="" else REPLY="" 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 */ /*******************/