Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
Re: Hooks
- X-seq: zsh-workers 22978
- From: Peter Stephenson <pws@xxxxxxx>
- To: "Zsh hackers list" <zsh-workers@xxxxxxxxxx>
- Subject: Re: Hooks
- Date: Tue, 7 Nov 2006 18:21:53 +0000
- In-reply-to: <dbfc82860611070711u322a6948m675ef9a38d097717@xxxxxxxxxxxxxx>
- Mailing-list: contact zsh-workers-help@xxxxxxxxxx; run by ezmlm
- Organization: Cambridge Silicon Radio
- References: <5db995410611060845y53f673e6je029a9c60659f116@xxxxxxxxxxxxxx> <20061106174053.GA4323@sc> <5db995410611061314l26e089b8wb214da46064c8235@xxxxxxxxxxxxxx> <20061106215051.GB4323@sc> <Pine.OSX.4.61.0611061617370.1112@xxxxxxxxxxxxxxx> <20061107081800.GA4420@sc> <20061107104916.d01e2fa5.pws@xxxxxxx> <dbfc82860611070711u322a6948m675ef9a38d097717@xxxxxxxxxxxxxx>
"Nikolai Weibull" <now@xxxxxxxx> wrote:
> > This is even further away from the original subject, but I've often felt
> > that functions like preexec and chpwd are getting a bit overloaded and
> > are unnecessarily hard to maintain automatically. It would be easy to
> > add an array which could contain names of functions to be executed,
> > similar to Emacs hooks.
>
> Yes, please do add.
This is it; it's not a particularly big change. I think the array names
precmd_functions etc. are obvious enough to be uncontroversial.
Index: Doc/Zsh/func.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/func.yo,v
retrieving revision 1.12
diff -u -r1.12 func.yo
--- Doc/Zsh/func.yo 20 Mar 2006 11:06:25 -0000 1.12
+++ Doc/Zsh/func.yo 7 Nov 2006 18:10:48 -0000
@@ -151,26 +151,44 @@
example(autoload +X myfunc)
sect(Special Functions)
-The following functions, if defined, have special meaning to
-the shell:
+Certain functions, if defined, have special meaning to the shell.
+
+In the case of tt(chpwd), tt(periodic), tt(precmd) and tt(preexec) it is
+possible to define an array that has the same name with `tt(_functions)'
+appended. Any element in such an array is taken as the name of a function
+to execute; it is executed in the same context and with the same arguments
+as the basic function. For example, if tt($chpwd_functions) is an array
+containing the values `tt(mychpwd)', `tt(chpwd_save_dirstack)', then the
+shell attempts to execute the functions `tt(chpwd)', `tt(mychpwd)' and
+`tt(chpwd_save_dirstack)', in that order. Any function that does not exist
+is silently ignored. A function found by this mechanism is referred to
+elsewhere as a `hook function'.
startitem()
findex(chpwd)
+vindex(chpwd_functions)
item(tt(chpwd))(
Executed whenever the current working directory is changed.
)
findex(periodic)
+vindex(periodic_functions)
item(tt(periodic))(
vindex(PERIOD)
If the parameter tt(PERIOD)
is set, this function is executed every tt($PERIOD)
-seconds, just before a prompt.
+seconds, just before a prompt. Note that if multiple functions
+are defined using the array tt(periodic_functions) only one
+period is applied to the complete set of functions, and the
+scheduled time is not reset if the list of functions is altered.
+Hence the set of functions is always called together.
)
findex(precmd)
+vindex(precmd_functions)
item(tt(precmd))(
Executed before each prompt.
)
findex(preexec)
+vindex(preexec_functions)
item(tt(preexec))(
Executed just after a command has been read and is about to be
executed. If the history mechanism is active (and the line was not
Index: Doc/Zsh/options.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/options.yo,v
retrieving revision 1.49
diff -u -r1.49 options.yo
--- Doc/Zsh/options.yo 1 Nov 2006 12:25:22 -0000 1.49
+++ Doc/Zsh/options.yo 7 Nov 2006 18:10:49 -0000
@@ -912,8 +912,11 @@
The check is omitted if the commands run from the previous command line
included a `tt(jobs)' command, since it is assumed the user is aware that
-there are background or suspended jobs. A `tt(jobs)' command run from the
-tt(precmd) function is not counted for this purpose.
+there are background or suspended jobs. A `tt(jobs)' command run from one
+of the hook functions defined in
+ifnzman(the section Special Functions in noderef(Functions))\
+ifzman(the section SPECIAL FUNCTIONS in zmanref(zshmisc))
+is not counted for this purpose.
)
pindex(HUP)
cindex(jobs, HUP)
Index: Src/builtin.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/builtin.c,v
retrieving revision 1.165
diff -u -r1.165 builtin.c
--- Src/builtin.c 5 Nov 2006 21:49:18 -0000 1.165
+++ Src/builtin.c 7 Nov 2006 18:10:50 -0000
@@ -1087,7 +1087,6 @@
static void
cd_new_pwd(int func, LinkNode dir)
{
- Eprog prog;
char *new_pwd, *s;
int dirstacksize;
@@ -1134,15 +1133,9 @@
}
/* execute the chpwd function */
- if ((prog = getshfunc("chpwd")) != &dummy_eprog) {
- int osc = sfcontext;
-
- fflush(stdout);
- fflush(stderr);
- sfcontext = SFC_HOOK;
- doshfunc("chpwd", prog, NULL, 0, 1);
- sfcontext = osc;
- }
+ fflush(stdout);
+ fflush(stderr);
+ callhookfunc("chpwd", NULL, 1);
dirstacksize = getiparam("DIRSTACKSIZE");
/* handle directory stack sizes out of range */
Index: Src/init.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/init.c,v
retrieving revision 1.70
diff -u -r1.70 init.c
--- Src/init.c 29 Sep 2006 20:43:33 -0000 1.70
+++ Src/init.c 7 Nov 2006 18:10:50 -0000
@@ -137,11 +137,9 @@
}
if (hend(prog)) {
int toksav = tok;
- Eprog preprog;
- if (toplevel && (preprog = getshfunc("preexec")) != &dummy_eprog) {
+ if (toplevel && getshfunc("preexec") != &dummy_eprog) {
LinkList args;
- int osc = sfcontext;
char *cmdstr;
args = znewlinklist();
@@ -155,10 +153,14 @@
zaddlinknode(args, getjobtext(prog, NULL));
zaddlinknode(args, cmdstr = getpermtext(prog, NULL));
- sfcontext = SFC_HOOK;
- doshfunc("preexec", preprog, args, 0, 1);
- sfcontext = osc;
+ callhookfunc("preexec", args, 1);
+
zsfree(cmdstr);
+ /*
+ * The following frees the nodes in the list, but
+ * doesn't free the data: the only data that
+ * needs freeing is cmdstr, just handled.
+ */
freelinklist(args, (FreeFunc) NULL);
errflag = 0;
}
Index: Src/utils.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/utils.c,v
retrieving revision 1.144
diff -u -r1.144 utils.c
--- Src/utils.c 19 Oct 2006 08:50:00 -0000 1.144
+++ Src/utils.c 7 Nov 2006 18:10:51 -0000
@@ -1079,28 +1079,53 @@
/**/
time_t lastwatch;
+/*
+ * Call a function given by "name" with optional arguments
+ * "lnklist". If "arrayp" is not zero, we also look through
+ * the array "name"_functions and execute functions found there.
+ */
+
/**/
mod_export int
-callhookfunc(char *name, LinkList lnklst)
+callhookfunc(char *name, LinkList lnklst, int arrayp)
{
Eprog prog;
-
- if ((prog = getshfunc(name)) != &dummy_eprog) {
/*
* 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;
+ int osc = sfcontext, osm = stopmsg, stat = 1;
+
+ sfcontext = SFC_HOOK;
- sfcontext = SFC_HOOK;
+ if ((prog = getshfunc(name)) != &dummy_eprog) {
doshfunc(name, prog, lnklst, 0, 1);
- sfcontext = osc;
- stopmsg = osm;
+ stat = 0;
+ }
- return 0;
+ if (arrayp) {
+ char **arrptr;
+ int namlen = strlen(name);
+#define HOOK_SUFFIX "_functions"
+#define HOOK_SUFFIX_LEN 11 /* including NUL byte */
+ VARARR(char, arrnam, namlen + HOOK_SUFFIX_LEN);
+ memcpy(arrnam, name, namlen);
+ memcpy(arrnam + namlen, HOOK_SUFFIX, HOOK_SUFFIX_LEN);
+
+ if ((arrptr = getaparam(arrnam))) {
+ for (; *arrptr; arrptr++) {
+ if ((prog = getshfunc(*arrptr)) != &dummy_eprog) {
+ doshfunc(arrnam, prog, lnklst, 0, 1);
+ stat = 0;
+ }
+ }
+ }
}
- return 1;
+ sfcontext = osc;
+ stopmsg = osm;
+
+ return stat;
}
/* do pre-prompt stuff */
@@ -1136,15 +1161,15 @@
/* If a shell function named "precmd" exists, *
* then execute it. */
- callhookfunc("precmd", NULL);
+ callhookfunc("precmd", NULL, 1);
if (errflag)
return;
- /* If 1) the parameter PERIOD exists, 2) the shell function *
+ /* If 1) the parameter PERIOD exists, 2) a hook function for *
* "periodic" exists, 3) it's been greater than PERIOD since we *
- * executed "periodic", then execute it now. */
+ * executed any such hook, then execute it now. */
if (period && (time(NULL) > lastperiodic + period) &&
- !callhookfunc("periodic", NULL))
+ !callhookfunc("periodic", NULL, 1))
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.93
diff -u -r1.93 zle_main.c
--- Src/Zle/zle_main.c 30 Oct 2006 14:13:39 -0000 1.93
+++ Src/Zle/zle_main.c 7 Nov 2006 18:10:51 -0000
@@ -716,7 +716,7 @@
# endif
- callhookfunc(lwatch_funcs[i], funcargs);
+ callhookfunc(lwatch_funcs[i], funcargs, 0);
if (errflag) {
/* No sensible way of handling errors here */
errflag = 0;
Index: Test/A05execution.ztst
===================================================================
RCS file: /cvsroot/zsh/zsh/Test/A05execution.ztst,v
retrieving revision 1.4
diff -u -r1.4 A05execution.ztst
--- Test/A05execution.ztst 29 Jul 2004 15:10:24 -0000 1.4
+++ Test/A05execution.ztst 7 Nov 2006 18:10:51 -0000
@@ -105,6 +105,18 @@
0q:chpwd
>Changed to $ZTST_testdir/command.tmp
+ chpwd() { print chpwd: changed to $PWD; }
+ chpwdfn1() { print chpwdfn1: changed to $PWD; }
+ chpwdfn2() { print chpwdfn2: changed to $PWD; }
+ chpwd_functions=(chpwdfn1 '' chpwdnonexistentfn chpwdfn2)
+ cd .
+ unfunction chpwd
+ unset chpwd_functions
+0q:chpwd_functions
+>chpwd: changed to $ZTST_testdir/command.tmp
+>chpwdfn1: changed to $ZTST_testdir/command.tmp
+>chpwdfn2: changed to $ZTST_testdir/command.tmp
+
# Hard to test periodic, precmd and preexec non-interactively.
fn() { TRAPEXIT() { print Exit; }; }
--
Peter Stephenson <pws@xxxxxxx> Software Engineer
CSR PLC, Churchill House, Cambridge Business Park, Cowley Road
Cambridge, CB4 0WZ, UK Tel: +44 (0)1223 692070
To access the latest news from CSR copy this link into a web browser: http://www.csr.com/email_sig.php
Messages sorted by:
Reverse Date,
Date,
Thread,
Author