From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 9058 invoked from network); 14 Jul 2008 21:27:24 -0000 X-Spam-Checker-Version: SpamAssassin 3.2.5 (2008-06-10) on f.primenet.com.au X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=AWL,BAYES_00,MISSING_HEADERS autolearn=no version=3.2.5 Received: from news.dotsrc.org (HELO a.mx.sunsite.dk) (130.225.247.88) by ns1.primenet.com.au with SMTP; 14 Jul 2008 21:27:24 -0000 Received-SPF: none (ns1.primenet.com.au: domain at sunsite.dk does not designate permitted sender hosts) Received: (qmail 46239 invoked from network); 14 Jul 2008 21:27:20 -0000 Received: from sunsite.dk (130.225.247.90) by a.mx.sunsite.dk with SMTP; 14 Jul 2008 21:27:20 -0000 Received: (qmail 1856 invoked by alias); 14 Jul 2008 21:27:16 -0000 Mailing-List: contact zsh-workers-help@sunsite.dk; run by ezmlm Precedence: bulk X-No-Archive: yes X-Seq: 25279 Received: (qmail 1838 invoked from network); 14 Jul 2008 21:27:16 -0000 Received: from bifrost.dotsrc.org (130.225.254.106) by sunsite.dk with SMTP; 14 Jul 2008 21:27:16 -0000 Received: from mtaout01-winn.ispmail.ntl.com (mtaout01-winn.ispmail.ntl.com [81.103.221.47]) by bifrost.dotsrc.org (Postfix) with ESMTP id 5B83F80525AB for ; Mon, 14 Jul 2008 23:27:11 +0200 (CEST) Received: from aamtaout04-winn.ispmail.ntl.com ([81.103.221.35]) by mtaout01-winn.ispmail.ntl.com with ESMTP id <20080714213203.EWXL28496.mtaout01-winn.ispmail.ntl.com@aamtaout04-winn.ispmail.ntl.com> for ; Mon, 14 Jul 2008 22:32:03 +0100 Received: from pws-pc ([81.107.40.67]) by aamtaout04-winn.ispmail.ntl.com with ESMTP id <20080714212717.IGNT18637.aamtaout04-winn.ispmail.ntl.com@pws-pc> for ; Mon, 14 Jul 2008 22:27:17 +0100 Date: Mon, 14 Jul 2008 22:27:00 +0100 From: Peter Stephenson Cc: zsh-workers@sunsite.dk (Zsh users list) Subject: PATCH: zshaddhistoryhook (was Re: history-beginning-local function) Message-ID: <20080714222700.1fe8cfd4@pws-pc> In-Reply-To: <1186.1216057340@csr.com> References: <1186.1216057340@csr.com> X-Mailer: Claws Mail 3.4.0 (GTK+ 2.12.11; x86_64-redhat-linux-gnu) Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit X-Virus-Scanned: ClamAV 0.92.1/7709/Mon Jul 14 18:16:52 2008 on bifrost X-Virus-Status: Clean On Mon, 14 Jul 2008 18:42:20 +0100 Peter Stephenson wrote: > The main problem is that you have to create and update the local history > file yourself since commands aren't saved to it. This is tricky since > it happens in the main shell after zle returns. We'd need a hook > function of some sort to be able to do the effect of fc -p around the > point the history is saved, unless there's a smarter way of doing it. (Switched to zsh-workers.) I think I've found quite a neat way of doing this, which kills another bird (that's been perching on a nearby rooftop for a long time occasionally looking hungrily into the fishpond) with the same stone and very little new, er, fish. However, although this does seem to work, I'm not 100% sure this doesn't have odd effects in the history. Wayne may have some notion. This adds the hook zshaddhistory at the point an interactive history line is saved. It has two bits of magic. Firstly, you can return non-zero from one of the hook functions (i.e the zshaddhistory function itself or one of the functions listed in zshaddhistory_functions) to ignore the line in exactly the same way as the existing mechanism for ignoring history entries. This kills the other bird. Secondly, if you call "fc -p" within the function it switches the history context for the current line handling, and the calling function will obligingly pop the context back the way it was before. So we can nicely reuse this mechanism to do all the dirty work for us. This sets things up so we can handle history-beginning-local (no code for that yet). Note I haven't tried this without INC_APPEND_HISTORY set. Index: Doc/Zsh/func.yo =================================================================== RCS file: /cvsroot/zsh/zsh/Doc/Zsh/func.yo,v retrieving revision 1.18 diff -u -r1.18 func.yo --- Doc/Zsh/func.yo 30 Jun 2008 10:37:13 -0000 1.18 +++ Doc/Zsh/func.yo 14 Jul 2008 21:21:03 -0000 @@ -241,6 +241,34 @@ elided); the third argument contains the full text that is being executed. ) +findex(zshaddhistory) +vindex(zshaddhistory_functions) +item(tt(zshaddhistory))( +cindex(history, hook when line is saved) +Executed when a history line has been read interactively, but +before it is executed. The sole argument is the complete history +line (so that any terminating newline will still be present). + +If any of the hook functions return a non-zero value the history +line will not be saved, although it lingers in the history until the +next line is executed allow you to reuse or edit it immediately. + +A hook function may call `tt(fc -p) var(...)' to switch the history +context so that the history is saved in a different file from the +that in the global tt(HISTFILE) parameter. This is handled specially: +the history context is automatically restored after the processing +of the history line is finished. + +The following example function first adds the history line to the normal +history with the newline stripped, which is usually the correct behaviour. +Then it switches the history context so that the line will +be written to a history file in the current directory. + +example(zshaddhistory() { + print -s ${1%%$'\n'} + fc -p .zsh_local_history +}) +) findex(zshexit) vindex(zshexit_functions) item(tt(zshexit))( Index: Src/builtin.c =================================================================== RCS file: /cvsroot/zsh/zsh/Src/builtin.c,v retrieving revision 1.196 diff -u -r1.196 builtin.c --- Src/builtin.c 10 Jun 2008 08:50:51 -0000 1.196 +++ Src/builtin.c 14 Jul 2008 21:21:05 -0000 @@ -1139,7 +1139,7 @@ fflush(stdout); fflush(stderr); if (!quiet) - callhookfunc("chpwd", NULL, 1); + callhookfunc("chpwd", NULL, 1, NULL); dirstacksize = getiparam("DIRSTACKSIZE"); /* handle directory stack sizes out of range */ @@ -4578,7 +4578,7 @@ lastval = val; if (sigtrapped[SIGEXIT]) dotrap(SIGEXIT); - callhookfunc("zshexit", NULL, 1); + callhookfunc("zshexit", NULL, 1, NULL); runhookdef(EXITHOOK, NULL); if (opts[MONITOR] && interact && (SHTTY != -1)) { release_pgrp(); Index: Src/exec.c =================================================================== RCS file: /cvsroot/zsh/zsh/Src/exec.c,v retrieving revision 1.133 diff -u -r1.133 exec.c --- Src/exec.c 30 Jun 2008 10:37:14 -0000 1.133 +++ Src/exec.c 14 Jul 2008 21:21:06 -0000 @@ -4093,6 +4093,16 @@ /* * execute a shell function * + * name is the name of the function + * + * prog is the code to execute + * + * doshargs, if set, are parameters to pass to the function, + * in which the first element is the function name (even if + * FUNCTIONARGZERO is set as this is handled inside this function). + * + * flags are a set of the PM_ flags associated with the function. + * * If noreturnval is nonzero, then reset the current return * value (lastval) to its value before the shell function * was executed. However, in any case return the status value @@ -4160,6 +4170,7 @@ oargv0 = argzero; argzero = ztrdup(getdata(node)); } + /* first node contains name regardless of option */ node = node->next; for (; node; node = node->next, x++) *x = ztrdup(getdata(node)); Index: Src/hist.c =================================================================== RCS file: /cvsroot/zsh/zsh/Src/hist.c,v retrieving revision 1.79 diff -u -r1.79 hist.c --- Src/hist.c 5 May 2008 14:29:03 -0000 1.79 +++ Src/hist.c 14 Jul 2008 21:21:07 -0000 @@ -130,8 +130,7 @@ /* Bits of histactive variable */ #define HA_ACTIVE (1<<0) /* History mechanism is active */ -#define HA_NOSTORE (1<<1) /* Don't store the line when finished */ -#define HA_NOINC (1<<2) /* Don't store, curhist not incremented */ +#define HA_NOINC (1<<1) /* Don't store, curhist not incremented */ /* Array of word beginnings and endings in current history line. */ @@ -180,6 +179,30 @@ static zlong defev; +/* Remember the last line in the history file so we can find it again. */ +static struct histfile_stats { + char *text; + time_t stim, mtim; + off_t fpos, fsiz; + zlong next_write_ev; +} lasthist; + +static struct histsave { + struct histfile_stats lasthist; + char *histfile; + HashTable histtab; + Histent hist_ring; + zlong curhist; + zlong histlinect; + zlong histsiz; + zlong savehistsiz; + int locallevel; +} *histsave_stack; +static int histsave_stack_size = 0; +static int histsave_stack_pos = 0; + +static zlong histfile_linect; + /* add a character to the current history word */ static void @@ -1082,7 +1105,8 @@ mod_export int hend(Eprog prog) { - int flag, save = 1; + LinkList hookargs = newlinklist(); + int flag, save = 1, hookret, stack_pos = histsave_stack_pos; char *hf; DPUTS(stophist != 2 && !(inbufflags & INP_ALIAS) && !chline, @@ -1092,7 +1116,7 @@ settyinfo(&shttyinfo); if (!(histactive & HA_NOINC)) unlinkcurline(); - if (histactive & (HA_NOSTORE|HA_NOINC)) { + if (histactive & HA_NOINC) { zfree(chline, hlinesz); zfree(chwords, chwordlen*sizeof(short)); chline = NULL; @@ -1103,6 +1127,10 @@ if (hist_ignore_all_dups != isset(HISTIGNOREALLDUPS) && (hist_ignore_all_dups = isset(HISTIGNOREALLDUPS)) != 0) histremovedups(); + + addlinknode(hookargs, "zshaddhistory"); + addlinknode(hookargs, chline); + callhookfunc("zshaddhistory", hookargs, 1, &hookret); /* For history sharing, lock history file once for both read and write */ hf = getsparam("HISTFILE"); if (isset(SHAREHISTORY) && lockhistfile(hf, 0)) { @@ -1123,7 +1151,7 @@ } if (chwordpos <= 2) save = 0; - else if (should_ignore_line(prog)) + else if (hookret || should_ignore_line(prog)) save = -1; } if (flag & (HISTFLAG_DONE | HISTFLAG_RECALL)) { @@ -1203,6 +1231,12 @@ if (isset(SHAREHISTORY)? histfileIsLocked() : isset(INCAPPENDHISTORY)) savehistfile(hf, 0, HFILE_USE_OPTIONS | HFILE_FAST); unlockhistfile(hf); /* It's OK to call this even if we aren't locked */ + /* + * No good reason for the user to push the history more than once, but + * it's easy to be tidy... + */ + while (histsave_stack_pos > stack_pos) + pophiststack(); unqueue_signals(); return !(flag & HISTFLAG_NOEXEC || errflag); } @@ -1942,30 +1976,6 @@ } } -/* Remember the last line in the history file so we can find it again. */ -static struct histfile_stats { - char *text; - time_t stim, mtim; - off_t fpos, fsiz; - zlong next_write_ev; -} lasthist; - -static struct histsave { - struct histfile_stats lasthist; - char *histfile; - HashTable histtab; - Histent hist_ring; - zlong curhist; - zlong histlinect; - zlong histsiz; - zlong savehistsiz; - int locallevel; -} *histsave_stack; -static int histsave_stack_size = 0; -static int histsave_stack_pos = 0; - -static zlong histfile_linect; - static int readhistline(int start, char **bufp, int *bufsiz, FILE *in) { Index: Src/init.c =================================================================== RCS file: /cvsroot/zsh/zsh/Src/init.c,v retrieving revision 1.85 diff -u -r1.85 init.c --- Src/init.c 12 May 2008 13:50:42 -0000 1.85 +++ Src/init.c 14 Jul 2008 21:21:07 -0000 @@ -175,7 +175,7 @@ addlinknode(args, dupstring(getjobtext(prog, NULL))); addlinknode(args, cmdstr = getpermtext(prog, NULL)); - callhookfunc("preexec", args, 1); + callhookfunc("preexec", args, 1, NULL); /* The only permanent storage is from getpermtext() */ zsfree(cmdstr); Index: Src/utils.c =================================================================== RCS file: /cvsroot/zsh/zsh/Src/utils.c,v retrieving revision 1.195 diff -u -r1.195 utils.c --- Src/utils.c 1 Jul 2008 08:36:02 -0000 1.195 +++ Src/utils.c 14 Jul 2008 21:21:09 -0000 @@ -1117,25 +1117,31 @@ /* * Call a function given by "name" with optional arguments - * "lnklist". If "arrayp" is not zero, we also look through + * "lnklist". If these are present the first argument is the function name. + * + * If "arrayp" is not zero, we also look through * the array "name"_functions and execute functions found there. + * + * If "retval" is not NULL, the return value of the first hook function to + * return non-zero is stored in *"retval". The return value is not otherwise + * available as the calling context is restored. */ /**/ mod_export int -callhookfunc(char *name, LinkList lnklst, int arrayp) +callhookfunc(char *name, LinkList lnklst, int arrayp, int *retval) { Eprog prog; /* * Save stopmsg, since user doesn't get a chance to respond * to a list of jobs generated in a hook. */ - int osc = sfcontext, osm = stopmsg, stat = 1; + int osc = sfcontext, osm = stopmsg, stat = 1, ret = 0; sfcontext = SFC_HOOK; if ((prog = getshfunc(name)) != &dummy_eprog) { - doshfunc(name, prog, lnklst, 0, 1); + ret = doshfunc(name, prog, lnklst, 0, 1); stat = 0; } @@ -1151,7 +1157,9 @@ if ((arrptr = getaparam(arrnam))) { for (; *arrptr; arrptr++) { if ((prog = getshfunc(*arrptr)) != &dummy_eprog) { - doshfunc(arrnam, prog, lnklst, 0, 1); + int newret = doshfunc(arrnam, prog, lnklst, 0, 1); + if (!ret) + ret = newret; stat = 0; } } @@ -1161,6 +1169,8 @@ sfcontext = osc; stopmsg = osm; + if (retval) + *retval = ret; return stat; } @@ -1200,7 +1210,7 @@ /* If a shell function named "precmd" exists, * * then execute it. */ - callhookfunc("precmd", NULL, 1); + callhookfunc("precmd", NULL, 1, NULL); if (errflag) return; @@ -1208,7 +1218,7 @@ * "periodic" exists, 3) it's been greater than PERIOD since we * * executed any such hook, then execute it now. */ if (period && (time(NULL) > lastperiodic + period) && - !callhookfunc("periodic", NULL, 1)) + !callhookfunc("periodic", NULL, 1, NULL)) lastperiodic = time(NULL); if (errflag) return; Index: Src/Zle/zle_main.c =================================================================== RCS file: /cvsroot/zsh/zsh/Src/Zle/zle_main.c,v retrieving revision 1.112 diff -u -r1.112 zle_main.c --- Src/Zle/zle_main.c 12 May 2008 13:50:43 -0000 1.112 +++ Src/Zle/zle_main.c 14 Jul 2008 21:21:10 -0000 @@ -736,7 +736,7 @@ # endif - callhookfunc(lwatch_funcs[i], funcargs, 0); + callhookfunc(lwatch_funcs[i], funcargs, 0, NULL); if (errflag) { /* No sensible way of handling errors here */ errflag = 0; -- Peter Stephenson Web page now at http://homepage.ntlworld.com/p.w.stephenson/