1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-10-23 04:30:24 +02:00

25272: add zshaddhistory hook

This commit is contained in:
Peter Stephenson 2008-07-17 11:27:55 +00:00
parent 4f7cf022b6
commit 0409391c7d
9 changed files with 117 additions and 49 deletions

View file

@ -1,3 +1,10 @@
2008-07-17 Peter Stephenson <pws@csr.com>
* 25279: Doc/Zsh/func.yo, Functions/Misc/add-zsh-hook,
Src/builtin.c, Src/exec.c, Src/hist.c, Src/init.c, Src/utils.c,
Src/Zle/zle_main.c: add zshaddhistory hook to allow manipulations
when history line is saved.
2008-07-15 Peter Stephenson <pws@csr.com>
* users/13036: Src/utils.c: "." is a valid character in

View file

@ -241,6 +241,34 @@ size-limited version of the command (with things like function bodies
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 -sr -- ${1%%$'\n'}
fc -p .zsh_local_history
})
)
findex(zshexit)
vindex(zshexit_functions)
item(tt(zshexit))(

View file

@ -1,6 +1,6 @@
# Add to HOOK the given FUNCTION.
# HOOK is one of chpwd, precmd, preexec, periodic, zshexit (the
# _functions subscript is not required).
# HOOK is one of chpwd, precmd, preexec, periodic, zshaddhistory,
# zshexit (the _functions subscript is not required).
#
# With -d, remove the function from the hook instead; delete the hook
# variable if it is empty.
@ -9,19 +9,19 @@
# function name, so any matching function will be deleted from the hook.
#
# Without -d, the FUNCTION is marked for autoload; -U is passed down to
# autoload if that is given. (This is harmless if the function is actually
# defined inline.)
# autoload if that is given, as are -z and -k. (This is harmless if the
# function is actually defined inline.)
emulate -L zsh
local -a hooktypes
hooktypes=(chpwd precmd preexec periodic zshexit)
hooktypes=(chpwd precmd preexec periodic zshaddhistory zshexit)
local opt
local -a autoopts
integer del
while getopts "dDU" opt; do
while getopts "dDUzk" opt; do
case $opt in
(d)
del=1
@ -31,7 +31,7 @@ while getopts "dDU" opt; do
del=2
;;
(U)
([Uzk])
autoopts+=(-$opt)
;;
@ -60,7 +60,9 @@ if (( del )); then
fi
# unset if no remaining entries --- this can give better
# performance in some cases
(( ${(P)#hook} )) || unset $hook
if (( ! ${(P)#hook} )); then
unset $hook
fi
fi
else
if (( ${(P)+hook} )); then

View file

@ -736,7 +736,7 @@ raw_getbyte(long do_keytmout, char *cptr)
# 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;

View file

@ -1139,7 +1139,7 @@ cd_new_pwd(int func, LinkNode dir, int quiet)
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 @@ zexit(int val, int from_where)
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();

View file

@ -4093,6 +4093,16 @@ loadautofn(Shfunc shf, int fksh, int autol)
/*
* 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 @@ doshfunc(char *name, Eprog prog, LinkList doshargs, int flags, int noreturnval)
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));

View file

@ -130,8 +130,7 @@ mod_export int hist_skip_flags;
/* 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 @@ int hlinesz;
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 @@ should_ignore_line(Eprog prog)
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 @@ hend(Eprog prog)
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 @@ hend(Eprog prog)
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 @@ hend(Eprog prog)
}
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 @@ hend(Eprog prog)
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 @@ resizehistents(void)
}
}
/* 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)
{

View file

@ -175,7 +175,7 @@ loop(int toplevel, int justonce)
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);

View file

@ -1117,25 +1117,31 @@ time_t lastwatch;
/*
* 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 @@ callhookfunc(char *name, LinkList lnklst, int arrayp)
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 @@ callhookfunc(char *name, LinkList lnklst, int arrayp)
sfcontext = osc;
stopmsg = osm;
if (retval)
*retval = ret;
return stat;
}
@ -1200,7 +1210,7 @@ preprompt(void)
/* 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 @@ preprompt(void)
* "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;