mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-10-29 05:21:00 +01: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>
|
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
|
* 28886: Src/Zle/zle_utils.c: Fix 28772 for the case where
|
||||||
regions have the "P" flag to include $PREDISPLAY in the
|
regions have the "P" flag to include $PREDISPLAY in the
|
||||||
offsets.
|
offsets.
|
||||||
|
|
@ -14316,5 +14322,5 @@
|
||||||
|
|
||||||
*****************************************************
|
*****************************************************
|
||||||
* This is used by the shell to define $ZSH_PATCHLEVEL
|
* This is used by the shell to define $ZSH_PATCHLEVEL
|
||||||
* $Revision: 1.5218 $
|
* $Revision: 1.5219 $
|
||||||
*****************************************************
|
*****************************************************
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,15 @@
|
||||||
#autoload
|
#autoload
|
||||||
|
|
||||||
if [[ -n $functions[zsh_directory_name] ]]; then
|
local func
|
||||||
zsh_directory_name c
|
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
|
else
|
||||||
_message 'dynamic directory name: implemented as zsh_directory_name c'
|
_message 'dynamic directory name: implemented as zsh_directory_name c'
|
||||||
fi
|
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
|
The shell function tt(add-zsh-hook) provides a simple way of adding or
|
||||||
removing functions from the array.
|
removing functions from the array.
|
||||||
|
|
||||||
var(hook) is one of tt(chpwd), tt(periodic), tt(precmd) or tt(preexec),
|
var(hook) is one of tt(chpwd), tt(periodic), tt(precmd), tt(preexec),
|
||||||
the special functions in question.
|
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
|
are given this will be added to the array of functions to be executed
|
||||||
in the given context.
|
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
|
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
|
and any matching names of functions are removed from the array of
|
||||||
functions to be executed.
|
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()
|
enditem()
|
||||||
|
|
||||||
|
|
@ -544,36 +551,15 @@ enditem()
|
||||||
subsect(Use with dynamic directory naming)
|
subsect(Use with dynamic directory naming)
|
||||||
|
|
||||||
It is possible to refer to recent directories using the dynamic directory
|
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
|
name syntax by using the supplied function tt(zsh_directory_name_cdr)
|
||||||
autoload a function tt(zsh_directory_name) containing the following code,
|
a hook:
|
||||||
tt(~[1]) will refer to the most recent directory other than $PWD, and so on.
|
|
||||||
This also includes completion.
|
|
||||||
|
|
||||||
example(if [[ $1 = n ]]; then
|
example(autoload -Uz add-zsh-hook
|
||||||
if [[ $2 = <-> ]]; then
|
add-zsh-hook -Uz zsh_directory_name zsh_directory_name_cdr)
|
||||||
# Recent directory
|
|
||||||
typeset -ga reply
|
When this is done, tt(~[1]) will refer to the most recent
|
||||||
autoload -Uz cdr
|
directory other than $PWD, and so on. Completion after tt(~[)var(...)
|
||||||
cdr -r
|
also works.
|
||||||
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)
|
|
||||||
|
|
||||||
subsect(Details of directory handling)
|
subsect(Details of directory handling)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1517,8 +1517,12 @@ cindex(directories, named, dynamic)
|
||||||
cindex(named directories, dynamic)
|
cindex(named directories, dynamic)
|
||||||
cindex(dynamic named directories)
|
cindex(dynamic named directories)
|
||||||
|
|
||||||
The feature described here is only available if the shell function
|
If the function tt(zsh_directory_name) exists, or the shell variable
|
||||||
tt(zsh_directory_name) exists.
|
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
|
A `tt(~)' followed by a string var(namstr) in unquoted square brackets is
|
||||||
treated specially as a dynamic directory name. Note that the first
|
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
|
(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
|
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
|
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
|
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
|
arguments: the string tt(d) (for directory) and the candidate for dynamic
|
||||||
naming. The function should either return non-zero status, if the
|
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
|
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
|
length matched (16 in the example) is longer than that matched by any
|
||||||
static name.
|
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
|
complete dynamic names for directories. The code for this should be
|
||||||
as for any other completion function as described in
|
as for any other completion function as described in
|
||||||
ifnzman(noderef(Completion System))\
|
ifnzman(noderef(Completion System))\
|
||||||
|
|
|
||||||
|
|
@ -5,4 +5,5 @@ _cdr
|
||||||
chpwd_recent_add
|
chpwd_recent_add
|
||||||
chpwd_recent_dirs
|
chpwd_recent_dirs
|
||||||
chpwd_recent_filehandler
|
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.
|
# Add to HOOK the given FUNCTION.
|
||||||
# HOOK is one of chpwd, precmd, preexec, periodic, zshaddhistory,
|
# 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
|
# With -d, remove the function from the hook instead; delete the hook
|
||||||
# variable if it is empty.
|
# variable if it is empty.
|
||||||
|
|
@ -15,7 +15,10 @@
|
||||||
emulate -L zsh
|
emulate -L zsh
|
||||||
|
|
||||||
local -a hooktypes
|
local -a hooktypes
|
||||||
hooktypes=(chpwd precmd preexec periodic zshaddhistory zshexit)
|
hooktypes=(
|
||||||
|
chpwd precmd preexec periodic zshaddhistory zshexit
|
||||||
|
zsh_directory_name
|
||||||
|
)
|
||||||
|
|
||||||
local opt
|
local opt
|
||||||
local -a autoopts
|
local -a autoopts
|
||||||
|
|
|
||||||
|
|
@ -579,7 +579,6 @@ filesubstr(char **namptr, int assign)
|
||||||
char *str = *namptr;
|
char *str = *namptr;
|
||||||
|
|
||||||
if (*str == Tilde && str[1] != '=' && str[1] != Equals) {
|
if (*str == Tilde && str[1] != '=' && str[1] != Equals) {
|
||||||
Shfunc dirfunc;
|
|
||||||
char *ptr, *tmp, *res, *ptr2;
|
char *ptr, *tmp, *res, *ptr2;
|
||||||
int val;
|
int val;
|
||||||
|
|
||||||
|
|
@ -594,12 +593,11 @@ filesubstr(char **namptr, int assign)
|
||||||
*namptr = dyncat((tmp = oldpwd) ? tmp : pwd, str + 2);
|
*namptr = dyncat((tmp = oldpwd) ? tmp : pwd, str + 2);
|
||||||
return 1;
|
return 1;
|
||||||
} else if (str[1] == Inbrack &&
|
} else if (str[1] == Inbrack &&
|
||||||
(dirfunc = getshfunc("zsh_directory_name")) &&
|
|
||||||
(ptr2 = strchr(str+2, Outbrack))) {
|
(ptr2 = strchr(str+2, Outbrack))) {
|
||||||
char **arr;
|
char **arr;
|
||||||
untokenize(tmp = dupstrpfx(str+2, ptr2 - (str+2)));
|
untokenize(tmp = dupstrpfx(str+2, ptr2 - (str+2)));
|
||||||
remnulargs(tmp);
|
remnulargs(tmp);
|
||||||
arr = subst_string_by_func(dirfunc, "n", tmp);
|
arr = subst_string_by_hook("zsh_directory_name", "n", tmp);
|
||||||
res = arr ? *arr : NULL;
|
res = arr ? *arr : NULL;
|
||||||
if (res) {
|
if (res) {
|
||||||
*namptr = dyncat(res, ptr2+1);
|
*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 struct nameddir homenode = { {NULL, "", 0}, NULL, 0 };
|
||||||
static int ffsz;
|
static int ffsz;
|
||||||
Shfunc func = getshfunc("zsh_directory_name");
|
char **ares;
|
||||||
|
int len;
|
||||||
|
|
||||||
/* Invalidate directory cache if argument is NULL. This is called *
|
/* Invalidate directory cache if argument is NULL. This is called *
|
||||||
* whenever a node is added to or removed from the hash table, and *
|
* whenever a node is added to or removed from the hash table, and *
|
||||||
|
|
@ -906,9 +907,16 @@ finddir(char *s)
|
||||||
return finddir_last = NULL;
|
return finddir_last = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* It's not safe to use the cache while we have function transformations.*/
|
#if 0
|
||||||
if(!func && !strcmp(s, finddir_full) && *finddir_full)
|
/*
|
||||||
|
* 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;
|
return finddir_last;
|
||||||
|
#endif
|
||||||
|
|
||||||
if ((int)strlen(s) >= ffsz) {
|
if ((int)strlen(s) >= ffsz) {
|
||||||
free(finddir_full);
|
free(finddir_full);
|
||||||
|
|
@ -920,18 +928,15 @@ finddir(char *s)
|
||||||
finddir_scan(&homenode.node, 0);
|
finddir_scan(&homenode.node, 0);
|
||||||
scanhashtable(nameddirtab, 0, 0, 0, finddir_scan, 0);
|
scanhashtable(nameddirtab, 0, 0, 0, finddir_scan, 0);
|
||||||
|
|
||||||
if (func) {
|
ares = subst_string_by_hook("zsh_directory_name", "d", finddir_full);
|
||||||
char **ares = subst_string_by_func(func, "d", finddir_full);
|
if (ares && arrlen(ares) >= 2 &&
|
||||||
int len;
|
(len = (int)zstrtol(ares[1], NULL, 10)) > finddir_best) {
|
||||||
if (ares && arrlen(ares) >= 2 &&
|
/* better duplicate this string since it's come from REPLY */
|
||||||
(len = (int)zstrtol(ares[1], NULL, 10)) > finddir_best) {
|
finddir_last = (Nameddir)hcalloc(sizeof(struct nameddir));
|
||||||
/* better duplicate this string since it's come from REPLY */
|
finddir_last->node.nam = zhtricat("[", dupstring(ares[0]), "]");
|
||||||
finddir_last = (Nameddir)hcalloc(sizeof(struct nameddir));
|
finddir_last->dir = dupstrpfx(finddir_full, len);
|
||||||
finddir_last->node.nam = zhtricat("[", dupstring(ares[0]), "]");
|
finddir_last->diff = len - strlen(finddir_last->node.nam);
|
||||||
finddir_last->dir = dupstrpfx(finddir_full, len);
|
finddir_best = len;
|
||||||
finddir_last->diff = len - strlen(finddir_last->node.nam);
|
|
||||||
finddir_best = len;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return finddir_last;
|
return finddir_last;
|
||||||
|
|
@ -3212,7 +3217,7 @@ getshfunc(char *nam)
|
||||||
char **
|
char **
|
||||||
subst_string_by_func(Shfunc func, char *arg1, char *orig)
|
subst_string_by_func(Shfunc func, char *arg1, char *orig)
|
||||||
{
|
{
|
||||||
int osc = sfcontext;
|
int osc = sfcontext, osm = stopmsg;
|
||||||
LinkList l = newlinklist();
|
LinkList l = newlinklist();
|
||||||
char **ret;
|
char **ret;
|
||||||
|
|
||||||
|
|
@ -3228,6 +3233,47 @@ subst_string_by_func(Shfunc func, char *arg1, char *orig)
|
||||||
ret = getaparam("reply");
|
ret = getaparam("reply");
|
||||||
|
|
||||||
sfcontext = osc;
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue