mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-09-02 10:01:11 +02:00
users/15864: turn zsh_directory_name into a hook
This commit is contained in:
parent
cc69ecfb9e
commit
f2dca9e155
9 changed files with 148 additions and 62 deletions
|
@ -1,5 +1,11 @@
|
|||
2011-03-11 Peter Stephenson <pws@csr.com>
|
||||
|
||||
* users/15864: Completion/Zsh/Context/_dynamic_directory_name,
|
||||
Doc/Zsh/contrib.yo, Doc/Zsh/expn.yo, Functions/Chpwd/.distfiles,
|
||||
Functions/Chpwd/zsh_directory_name_cdr,
|
||||
Functions/Misc/add-zsh-hook, Src/subst.c, Src/utils.c:
|
||||
turn zsh_directory_name into a hook.
|
||||
|
||||
* 28886: Src/Zle/zle_utils.c: Fix 28772 for the case where
|
||||
regions have the "P" flag to include $PREDISPLAY in the
|
||||
offsets.
|
||||
|
@ -14316,5 +14322,5 @@
|
|||
|
||||
*****************************************************
|
||||
* This is used by the shell to define $ZSH_PATCHLEVEL
|
||||
* $Revision: 1.5218 $
|
||||
* $Revision: 1.5219 $
|
||||
*****************************************************
|
||||
|
|
|
@ -1,7 +1,15 @@
|
|||
#autoload
|
||||
|
||||
if [[ -n $functions[zsh_directory_name] ]]; then
|
||||
zsh_directory_name c
|
||||
local func
|
||||
integer ret=1
|
||||
|
||||
if [[ -n $functions[zsh_directory_name] || \
|
||||
${+zsh_directory_name_functions} -ne 0 ]] ; then
|
||||
zsh_directory_name c && ret=0
|
||||
for func in $zsh_directory_name_functions; do
|
||||
$func c && ret=0
|
||||
done
|
||||
return ret
|
||||
else
|
||||
_message 'dynamic directory name: implemented as zsh_directory_name c'
|
||||
fi
|
||||
|
|
|
@ -302,10 +302,13 @@ called at the same point; these are so-called `hook functions'.
|
|||
The shell function tt(add-zsh-hook) provides a simple way of adding or
|
||||
removing functions from the array.
|
||||
|
||||
var(hook) is one of tt(chpwd), tt(periodic), tt(precmd) or tt(preexec),
|
||||
the special functions in question.
|
||||
var(hook) is one of tt(chpwd), tt(periodic), tt(precmd), tt(preexec),
|
||||
tt(zshaddhistory), tt(zshexit), or tt(zsh_directory_name),
|
||||
the special functions in question. Note that tt(zsh_directory_name)
|
||||
is called in a different way from the other functions, but may
|
||||
still be manipulated as a hook.
|
||||
|
||||
var(functions) is name of an ordinary shell function. If no options
|
||||
var(function) is name of an ordinary shell function. If no options
|
||||
are given this will be added to the array of functions to be executed
|
||||
in the given context.
|
||||
|
||||
|
@ -315,6 +318,10 @@ the array of functions to be executed.
|
|||
If the option tt(-D) is given, the var(function) is treated as a pattern
|
||||
and any matching names of functions are removed from the array of
|
||||
functions to be executed.
|
||||
|
||||
The options tt(-U), tt(-z) and tt(-k) are passed as arguments to
|
||||
tt(autoload) for var(function). For functions contributed with zsh, the
|
||||
options tt(-Uz) are appropriate.
|
||||
)
|
||||
enditem()
|
||||
|
||||
|
@ -544,36 +551,15 @@ enditem()
|
|||
subsect(Use with dynamic directory naming)
|
||||
|
||||
It is possible to refer to recent directories using the dynamic directory
|
||||
name syntax that appeared in zsh version 4.3.7. If you create and
|
||||
autoload a function tt(zsh_directory_name) containing the following code,
|
||||
tt(~[1]) will refer to the most recent directory other than $PWD, and so on.
|
||||
This also includes completion.
|
||||
name syntax by using the supplied function tt(zsh_directory_name_cdr)
|
||||
a hook:
|
||||
|
||||
example(if [[ $1 = n ]]; then
|
||||
if [[ $2 = <-> ]]; then
|
||||
# Recent directory
|
||||
typeset -ga reply
|
||||
autoload -Uz cdr
|
||||
cdr -r
|
||||
if [[ -n ${reply[$2]} ]]; then
|
||||
reply=LPAR()${reply[$2]}RPAR()
|
||||
return 0
|
||||
else
|
||||
reply=LPAR()RPAR()
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
elif [[ $1 = c ]]; then
|
||||
if [[ $PREFIX = <-> || -z $PREFIX ]]; then
|
||||
typeset -a keys values
|
||||
values=LPAR()${${(f)"$+LPAR()cdr -l+RPAR()"}/ ##/:}RPAR()
|
||||
keys=LPAR()${values%%:*}RPAR()
|
||||
_describe -t dir-index 'recent directory index' \
|
||||
values keys -V unsorted -S']'
|
||||
return
|
||||
fi
|
||||
fi
|
||||
return 1)
|
||||
example(autoload -Uz add-zsh-hook
|
||||
add-zsh-hook -Uz zsh_directory_name zsh_directory_name_cdr)
|
||||
|
||||
When this is done, tt(~[1]) will refer to the most recent
|
||||
directory other than $PWD, and so on. Completion after tt(~[)var(...)
|
||||
also works.
|
||||
|
||||
subsect(Details of directory handling)
|
||||
|
||||
|
|
|
@ -1517,8 +1517,12 @@ cindex(directories, named, dynamic)
|
|||
cindex(named directories, dynamic)
|
||||
cindex(dynamic named directories)
|
||||
|
||||
The feature described here is only available if the shell function
|
||||
tt(zsh_directory_name) exists.
|
||||
If the function tt(zsh_directory_name) exists, or the shell variable
|
||||
tt(zsh_directory_name_functions) exists and contains an array of
|
||||
function names, then the functions are used to implement dynamic
|
||||
directory naming. The functions are tried in order until one returns
|
||||
status zero, so it is important that functions test whether they can
|
||||
handle the case in question and return an appropriate status.
|
||||
|
||||
A `tt(~)' followed by a string var(namstr) in unquoted square brackets is
|
||||
treated specially as a dynamic directory name. Note that the first
|
||||
|
@ -1529,11 +1533,12 @@ which is the directory corresponding to the name and return status zero
|
|||
(executing an assignment as the last statement is usually sufficient), or
|
||||
it should return status non-zero. In the former case the element of reply
|
||||
is used as the directory; in the latter case the substitution is deemed to
|
||||
have failed and tt(NOMATCH) handling is applied if the option is set.
|
||||
have failed. If all functions fail and the option tt(NOMATCH) is set,
|
||||
an error results.
|
||||
|
||||
The function tt(zsh_directory_name) is also used to see if a directory can
|
||||
The functions defined as above are also used to see if a directory can
|
||||
be turned into a name, for example when printing the directory stack or
|
||||
when expanding tt(%~) in prompts. In this case the function is passed two
|
||||
when expanding tt(%~) in prompts. In this case each function is passed two
|
||||
arguments: the string tt(d) (for directory) and the candidate for dynamic
|
||||
naming. The function should either return non-zero status, if the
|
||||
directory cannot be named by the function, or it should set the array reply
|
||||
|
@ -1551,7 +1556,15 @@ parts of the directory path, as described below; it is used if the prefix
|
|||
length matched (16 in the example) is longer than that matched by any
|
||||
static name.
|
||||
|
||||
The completion system calls `tt(zsh_directory_name c)' in order to
|
||||
It is not a requirement that a function implements both
|
||||
tt(n) and tt(d) calls; for example, it might be appropriate for certain
|
||||
dynamic forms of expansion not to be contracted to names. In that case
|
||||
any call with the first argument tt(d) should cause a non-zero status to
|
||||
be returned.
|
||||
|
||||
The completion system calls `tt(zsh_directory_name c)' followed by
|
||||
equivalent calls to elements of the array
|
||||
tt(zsh_directory_name_functions), if it exists, in order to
|
||||
complete dynamic names for directories. The code for this should be
|
||||
as for any other completion function as described in
|
||||
ifnzman(noderef(Completion System))\
|
||||
|
|
|
@ -5,4 +5,5 @@ _cdr
|
|||
chpwd_recent_add
|
||||
chpwd_recent_dirs
|
||||
chpwd_recent_filehandler
|
||||
zsh_directory_name_cdr
|
||||
'
|
||||
|
|
25
Functions/Chpwd/zsh_directory_name_cdr
Normal file
25
Functions/Chpwd/zsh_directory_name_cdr
Normal file
|
@ -0,0 +1,25 @@
|
|||
if [[ $1 = n ]]; then
|
||||
if [[ $2 = <-> ]]; then
|
||||
# Recent directory
|
||||
typeset -ga reply
|
||||
autoload -Uz cdr
|
||||
cdr -r
|
||||
if [[ -n ${reply[$2]} ]]; then
|
||||
reply=(${reply[$2]})
|
||||
return 0
|
||||
else
|
||||
reply=()
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
elif [[ $1 = c ]]; then
|
||||
if [[ $PREFIX = <-> || -z $PREFIX ]]; then
|
||||
typeset -a keys values
|
||||
values=(${${(f)"$(cdr -l)"}/ ##/:})
|
||||
keys=(${values%%:*})
|
||||
_describe -t dir-index 'recent directory index' \
|
||||
values keys -V unsorted -S']'
|
||||
return
|
||||
fi
|
||||
fi
|
||||
return 1
|
|
@ -1,6 +1,6 @@
|
|||
# Add to HOOK the given FUNCTION.
|
||||
# HOOK is one of chpwd, precmd, preexec, periodic, zshaddhistory,
|
||||
# zshexit (the _functions subscript is not required).
|
||||
# zshexit, zsh_directory_name (the _functions subscript is not required).
|
||||
#
|
||||
# With -d, remove the function from the hook instead; delete the hook
|
||||
# variable if it is empty.
|
||||
|
@ -15,7 +15,10 @@
|
|||
emulate -L zsh
|
||||
|
||||
local -a hooktypes
|
||||
hooktypes=(chpwd precmd preexec periodic zshaddhistory zshexit)
|
||||
hooktypes=(
|
||||
chpwd precmd preexec periodic zshaddhistory zshexit
|
||||
zsh_directory_name
|
||||
)
|
||||
|
||||
local opt
|
||||
local -a autoopts
|
||||
|
|
|
@ -579,7 +579,6 @@ filesubstr(char **namptr, int assign)
|
|||
char *str = *namptr;
|
||||
|
||||
if (*str == Tilde && str[1] != '=' && str[1] != Equals) {
|
||||
Shfunc dirfunc;
|
||||
char *ptr, *tmp, *res, *ptr2;
|
||||
int val;
|
||||
|
||||
|
@ -594,12 +593,11 @@ filesubstr(char **namptr, int assign)
|
|||
*namptr = dyncat((tmp = oldpwd) ? tmp : pwd, str + 2);
|
||||
return 1;
|
||||
} else if (str[1] == Inbrack &&
|
||||
(dirfunc = getshfunc("zsh_directory_name")) &&
|
||||
(ptr2 = strchr(str+2, Outbrack))) {
|
||||
char **arr;
|
||||
untokenize(tmp = dupstrpfx(str+2, ptr2 - (str+2)));
|
||||
remnulargs(tmp);
|
||||
arr = subst_string_by_func(dirfunc, "n", tmp);
|
||||
arr = subst_string_by_hook("zsh_directory_name", "n", tmp);
|
||||
res = arr ? *arr : NULL;
|
||||
if (res) {
|
||||
*namptr = dyncat(res, ptr2+1);
|
||||
|
|
78
Src/utils.c
78
Src/utils.c
|
@ -890,7 +890,8 @@ finddir(char *s)
|
|||
{
|
||||
static struct nameddir homenode = { {NULL, "", 0}, NULL, 0 };
|
||||
static int ffsz;
|
||||
Shfunc func = getshfunc("zsh_directory_name");
|
||||
char **ares;
|
||||
int len;
|
||||
|
||||
/* Invalidate directory cache if argument is NULL. This is called *
|
||||
* whenever a node is added to or removed from the hash table, and *
|
||||
|
@ -906,9 +907,16 @@ finddir(char *s)
|
|||
return finddir_last = NULL;
|
||||
}
|
||||
|
||||
/* It's not safe to use the cache while we have function transformations.*/
|
||||
if(!func && !strcmp(s, finddir_full) && *finddir_full)
|
||||
#if 0
|
||||
/*
|
||||
* It's not safe to use the cache while we have function
|
||||
* transformations, and it's not clear it's worth the
|
||||
* complexity of guessing here whether subst_string_by_hook
|
||||
* is going to turn up the goods.
|
||||
*/
|
||||
if (!strcmp(s, finddir_full) && *finddir_full)
|
||||
return finddir_last;
|
||||
#endif
|
||||
|
||||
if ((int)strlen(s) >= ffsz) {
|
||||
free(finddir_full);
|
||||
|
@ -920,18 +928,15 @@ finddir(char *s)
|
|||
finddir_scan(&homenode.node, 0);
|
||||
scanhashtable(nameddirtab, 0, 0, 0, finddir_scan, 0);
|
||||
|
||||
if (func) {
|
||||
char **ares = subst_string_by_func(func, "d", finddir_full);
|
||||
int len;
|
||||
if (ares && arrlen(ares) >= 2 &&
|
||||
(len = (int)zstrtol(ares[1], NULL, 10)) > finddir_best) {
|
||||
/* better duplicate this string since it's come from REPLY */
|
||||
finddir_last = (Nameddir)hcalloc(sizeof(struct nameddir));
|
||||
finddir_last->node.nam = zhtricat("[", dupstring(ares[0]), "]");
|
||||
finddir_last->dir = dupstrpfx(finddir_full, len);
|
||||
finddir_last->diff = len - strlen(finddir_last->node.nam);
|
||||
finddir_best = len;
|
||||
}
|
||||
ares = subst_string_by_hook("zsh_directory_name", "d", finddir_full);
|
||||
if (ares && arrlen(ares) >= 2 &&
|
||||
(len = (int)zstrtol(ares[1], NULL, 10)) > finddir_best) {
|
||||
/* better duplicate this string since it's come from REPLY */
|
||||
finddir_last = (Nameddir)hcalloc(sizeof(struct nameddir));
|
||||
finddir_last->node.nam = zhtricat("[", dupstring(ares[0]), "]");
|
||||
finddir_last->dir = dupstrpfx(finddir_full, len);
|
||||
finddir_last->diff = len - strlen(finddir_last->node.nam);
|
||||
finddir_best = len;
|
||||
}
|
||||
|
||||
return finddir_last;
|
||||
|
@ -3212,7 +3217,7 @@ getshfunc(char *nam)
|
|||
char **
|
||||
subst_string_by_func(Shfunc func, char *arg1, char *orig)
|
||||
{
|
||||
int osc = sfcontext;
|
||||
int osc = sfcontext, osm = stopmsg;
|
||||
LinkList l = newlinklist();
|
||||
char **ret;
|
||||
|
||||
|
@ -3228,6 +3233,47 @@ subst_string_by_func(Shfunc func, char *arg1, char *orig)
|
|||
ret = getaparam("reply");
|
||||
|
||||
sfcontext = osc;
|
||||
stopmsg = osm;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Front end to subst_string_by_func to use hook-like logic.
|
||||
* name can refer to a function, and name + "_hook" can refer
|
||||
* to an array containing a list of functions. The functions
|
||||
* are tried in order until one returns success.
|
||||
*/
|
||||
/**/
|
||||
char **
|
||||
subst_string_by_hook(char *name, char *arg1, char *orig)
|
||||
{
|
||||
Shfunc func;
|
||||
char **ret = NULL;
|
||||
|
||||
if ((func = getshfunc(name))) {
|
||||
ret = subst_string_by_func(func, arg1, orig);
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
char **arrptr;
|
||||
int namlen = strlen(name);
|
||||
VARARR(char, arrnam, namlen + HOOK_SUFFIX_LEN);
|
||||
memcpy(arrnam, name, namlen);
|
||||
memcpy(arrnam + namlen, HOOK_SUFFIX, HOOK_SUFFIX_LEN);
|
||||
|
||||
if ((arrptr = getaparam(arrnam))) {
|
||||
/* Guard against internal modification of the array */
|
||||
arrptr = arrdup(arrptr);
|
||||
for (; *arrptr; arrptr++) {
|
||||
if ((func = getshfunc(*arrptr))) {
|
||||
ret = subst_string_by_func(func, arg1, orig);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue