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:
parent
4f7cf022b6
commit
0409391c7d
9 changed files with 117 additions and 49 deletions
|
@ -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
|
||||
|
|
|
@ -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))(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
11
Src/exec.c
11
Src/exec.c
|
@ -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));
|
||||
|
|
68
Src/hist.c
68
Src/hist.c
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
24
Src/utils.c
24
Src/utils.c
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue