mirror of
git://git.code.sf.net/p/zsh/code
synced 2026-01-06 09:41:07 +01:00
improve filename completion; use accept-exact for in-path completion; new fake style (11971)
This commit is contained in:
parent
207758992a
commit
2769b19881
5 changed files with 233 additions and 54 deletions
|
|
@ -8,6 +8,10 @@
|
|||
|
||||
2000-06-19 Sven Wischnowsky <wischnow@zsh.org>
|
||||
|
||||
* 11971: Completion/Core/_path_files, Doc/Zsh/compsys.yo,
|
||||
Src/Zle/compcore.c, Src/Zle/computil.c: improve filename
|
||||
completion; use accept-exact for in-path completion; new fake style
|
||||
|
||||
* users/3188: Completion/Core/_description, Completion/Core/_setup,
|
||||
Doc/Zsh/compsys.yo: restore ZLS_COLORS when possible; better
|
||||
group-name handling in ZLS_COLORS
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
local linepath realpath donepath prepath testpath exppath skips skipped
|
||||
local tmp1 tmp2 tmp3 tmp4 i orig eorig pre suf tpre tsuf opre osuf cpre
|
||||
local pats haspats ignore pfxsfx sopt gopt opt sdirs ignpar cfopt
|
||||
local nm=$compstate[nmatches] menu matcher mopts sort match mid
|
||||
local nm=$compstate[nmatches] menu matcher mopts sort match mid accex fake
|
||||
|
||||
typeset -U prepaths exppaths
|
||||
|
||||
|
|
@ -139,12 +139,14 @@ else
|
|||
skips='((.|..)/)##'
|
||||
fi
|
||||
|
||||
zstyle -s ":completion:${curcontext}:paths" special-dirs sdirs &&
|
||||
[[ "$sdirs" = (yes|true|on|1) ]] && sdirs=yes
|
||||
zstyle -s ":completion:${curcontext}:paths" special-dirs sdirs
|
||||
|
||||
[[ "$pats" = ((|*[[:blank:]])\*(|[[:blank:]]*)|*\([^[:blank:]]#/[^[:blank:]]#\)*) ]] &&
|
||||
sopt=$sopt/
|
||||
|
||||
zstyle -a ":completion:${curcontext}:files" accept-exact accex
|
||||
zstyle -a ":completion:${curcontext}:files" fake fake
|
||||
|
||||
zstyle -s ":completion:${curcontext}:files" ignore-parents ignpar
|
||||
|
||||
if [[ -n "$compstate[pattern_match]" &&
|
||||
|
|
@ -314,33 +316,33 @@ for prepath in "$prepaths[@]"; do
|
|||
# Get the matching files by globbing.
|
||||
|
||||
if [[ "$tpre$tsuf" = */* ]]; then
|
||||
compfiles -P$cfopt tmp1 "$skipped" "$_matcher" "$sdirs"
|
||||
compfiles -P$cfopt tmp1 accex "$skipped" "$_matcher" "$sdirs" fake
|
||||
elif [[ "$sopt" = *[/f]* ]]; then
|
||||
compfiles -p$cfopt tmp1 "$skipped" "$_matcher" "$sdirs" "$pats[@]"
|
||||
compfiles -p$cfopt tmp1 accex "$skipped" "$_matcher" "$sdirs" fake "$pats[@]"
|
||||
else
|
||||
compfiles -p$cfopt tmp1 "$skipped" "$_matcher" '' "$pats[@]"
|
||||
compfiles -p$cfopt tmp1 accex "$skipped" "$_matcher" '' fake "$pats[@]"
|
||||
fi
|
||||
tmp1=( $~tmp1 )
|
||||
|
||||
if [[ -n "$PREFIX$SUFFIX" ]]; then
|
||||
# See which of them match what's on the line.
|
||||
|
||||
if [[ -n "$_comp_correct" ]]; then
|
||||
tmp2=( "$tmp1[@]" )
|
||||
builtin compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp1:t}"
|
||||
if [[ "$tmp1[1]" = */* ]]; then
|
||||
if [[ -n "$_comp_correct" ]]; then
|
||||
tmp2=( "$tmp1[@]" )
|
||||
builtin compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp1:t}"
|
||||
|
||||
if [[ $#tmp1 -eq 0 ]]; then
|
||||
tmp1=( "$tmp2[@]" )
|
||||
compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp2:t}"
|
||||
if [[ $#tmp1 -eq 0 ]]; then
|
||||
tmp1=( "$tmp2[@]" )
|
||||
compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp2:t}"
|
||||
fi
|
||||
else
|
||||
tmp2=( "$tmp1[@]" )
|
||||
compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp1:t}"
|
||||
fi
|
||||
else
|
||||
if [[ "$tmp1[1]" = */* ]]; then
|
||||
tmp2=( "$tmp1[@]" )
|
||||
else
|
||||
tmp2=( '' )
|
||||
fi
|
||||
|
||||
compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp1:t}"
|
||||
tmp2=( '' )
|
||||
compadd -D tmp1 -F _comp_ignore "$matcher[@]" -a tmp1
|
||||
fi
|
||||
|
||||
# If no file matches, save the expanded path and continue with
|
||||
|
|
@ -431,26 +433,18 @@ for prepath in "$prepaths[@]"; do
|
|||
tmp3="$pre$suf"
|
||||
tpre="$pre"
|
||||
tsuf="$suf"
|
||||
tmp1=( "${(@)tmp1#${prepath}${realpath}${testpath}}" )
|
||||
[[ -n "${prepath}${realpath}${testpath}" ]] &&
|
||||
tmp1=( "${(@)tmp1#${prepath}${realpath}${testpath}}" )
|
||||
|
||||
while true; do
|
||||
|
||||
# First we check if some of the files match the original string
|
||||
# for this component. If there are some we remove all other
|
||||
# names. This avoids having `foo' complete to `foo' and `foobar'.
|
||||
# The return value is non-zero if the component is ambiguous.
|
||||
|
||||
if [[ "$tmp3" = */* ]]; then
|
||||
tmp4=( "${(@M)tmp1:#${tmp3%%/*}/*}" )
|
||||
(( $#tmp4 )) && tmp1=( "$tmp4[@]" )
|
||||
fi
|
||||
|
||||
# Next we see if this component is ambiguous.
|
||||
|
||||
if [[ "$tmp3" = */* ]]; then
|
||||
tmp4=$tmp1[(I)^${${tmp1[1]%%/*}//(#b)([][\\<>(|)^#~*?])/\\$match[1]}/*]
|
||||
else
|
||||
tmp4=$tmp1[(I)^${tmp1[1]//(#b)([][\\<>(|)^#~*?])/\\$match[1]}]
|
||||
fi
|
||||
compfiles -r tmp1 "$tmp3"
|
||||
tmp4=$?
|
||||
|
||||
if [[ "$tpre" = */* ]]; then
|
||||
tmp2="${cpre}${tpre%%/*}"
|
||||
|
|
|
|||
|
|
@ -780,6 +780,13 @@ matches. If it is set to `true' for at least one match which is the
|
|||
same as the string on the line, this match will immediately be
|
||||
accepted.
|
||||
|
||||
When completing filenames (where it is looked up for the tt(files)
|
||||
tag), this style also accepts any number of patterns as the value. If
|
||||
this is used, pathnames matching one of these patterns will be
|
||||
accepted immediately even if the command line contains some more
|
||||
partially typed pathname components and these match no file under the
|
||||
directory accepted.
|
||||
|
||||
Note that this is also used by the tt(_expand) completer to decide if
|
||||
words beginning with a tilde or parameter expansion should be
|
||||
expanded. This means that if, for example, there are parameters
|
||||
|
|
@ -968,6 +975,17 @@ generated this way (e.g. due to the option tt(AUTO_MENU) being set),
|
|||
this will also cycle through the names of the files in pathname
|
||||
components after the first ambiguous one.
|
||||
)
|
||||
kindex(fake, completion style)
|
||||
item(tt(fake))(
|
||||
Currently, this style is only used when completing files and lookup up
|
||||
with the tag tt(files). Its values are of the form
|
||||
`var(dir)tt(:)var(names...)'. This will add the var(names) as
|
||||
possible matches when completing in the directory var(dir), even if no
|
||||
such files really exist.
|
||||
|
||||
This can be useful on systems that support special filesystems whose
|
||||
top-level pathnames can not be listed or generated with glob patterns.
|
||||
)
|
||||
kindex(file-patterns, completion style)
|
||||
item(tt(file-patterns))(
|
||||
In most places where filenames are completed, the function tt(_files)
|
||||
|
|
|
|||
|
|
@ -1914,8 +1914,8 @@ addmatches(Cadata dat, char **argv)
|
|||
if (aign || pign) {
|
||||
int il = ppl + sl + psl, addit = 1;
|
||||
|
||||
if (il > ilen)
|
||||
ibuf = (char *) zhalloc((ilen = il) + 1);
|
||||
if (il + 1> ilen)
|
||||
ibuf = (char *) zhalloc((ilen = il) + 2);
|
||||
|
||||
if (ppl)
|
||||
memcpy(ibuf, dat->ppre, ppl);
|
||||
|
|
|
|||
|
|
@ -3058,17 +3058,37 @@ bin_compfmt(char *nam, char **args, char *ops, int func)
|
|||
#define PATH_MAX2 (PATH_MAX * 2)
|
||||
|
||||
static LinkList
|
||||
cfp_test_exact(LinkList names, char *skipped)
|
||||
cfp_test_exact(LinkList names, char **accept, char *skipped)
|
||||
{
|
||||
char buf[PATH_MAX2 + 1], *suf, *p;
|
||||
int l, sl, found = 0;
|
||||
struct stat st;
|
||||
LinkNode node;
|
||||
LinkList ret = newlinklist();
|
||||
LinkList ret = newlinklist(), alist = NULL;
|
||||
|
||||
if (!(compprefix && *compprefix) && !(compsuffix && *compsuffix))
|
||||
if ((!(compprefix && *compprefix) && !(compsuffix && *compsuffix)) ||
|
||||
(!accept || !*accept ||
|
||||
((!strcmp(*accept, "false") || !strcmp(*accept, "no") ||
|
||||
!strcmp(*accept, "off") || !strcmp(*accept, "0")) && !accept[1])))
|
||||
return NULL;
|
||||
|
||||
if (accept[1] ||
|
||||
(strcmp(*accept, "true") && strcmp(*accept, "yes") &&
|
||||
strcmp(*accept, "on") && strcmp(*accept, "1"))) {
|
||||
Patprog prog;
|
||||
|
||||
alist = newlinklist();
|
||||
|
||||
for (; (p = *accept); accept++) {
|
||||
if (*p == '*' && !p[1]) {
|
||||
alist = NULL;
|
||||
break;
|
||||
}
|
||||
tokenize(p = dupstring(p));
|
||||
if ((prog = patcompile(p, 0, NULL)))
|
||||
addlinknode(alist, prog);
|
||||
}
|
||||
}
|
||||
sl = strlen(skipped) + (compprefix ? strlen(compprefix) : 0) +
|
||||
(compsuffix ? strlen(compsuffix) : 0);
|
||||
|
||||
|
|
@ -3078,11 +3098,22 @@ cfp_test_exact(LinkList names, char *skipped)
|
|||
suf = dyncat(skipped, rembslash(dyncat(compprefix, compsuffix)));
|
||||
|
||||
for (node = firstnode(names); node; incnode(node)) {
|
||||
if ((l = strlen(p = (char *) getdata(node))) && l + sl < PATH_MAX2) {
|
||||
l = strlen(p = (char *) getdata(node));
|
||||
if (l + sl < PATH_MAX2) {
|
||||
strcpy(buf, p);
|
||||
strcpy(buf + l, suf);
|
||||
|
||||
if (!ztat(buf, &st, 0) && S_ISDIR(st.st_mode)) {
|
||||
if (!ztat(buf, &st, 0)) {
|
||||
if (alist) {
|
||||
LinkNode anode;
|
||||
|
||||
for (anode = firstnode(alist); anode; incnode(anode))
|
||||
if (pattry((Patprog) getdata(anode), buf))
|
||||
break;
|
||||
|
||||
if (!anode)
|
||||
continue;
|
||||
}
|
||||
found = 1;
|
||||
addlinknode(ret, dupstring(buf));
|
||||
}
|
||||
|
|
@ -3334,12 +3365,14 @@ cfp_bld_pats(int dirs, LinkList names, char *skipped, char **pats)
|
|||
}
|
||||
|
||||
static LinkList
|
||||
cfp_add_sdirs(LinkList final, LinkList orig, char *skipped, char *sdirs)
|
||||
cfp_add_sdirs(LinkList final, LinkList orig, char *skipped,
|
||||
char *sdirs, char **fake)
|
||||
{
|
||||
int add = 0;
|
||||
|
||||
if (*sdirs) {
|
||||
if (!strcmp(sdirs, "yes"))
|
||||
if (*sdirs && (isset(GLOBDOTS) || (compprefix && *compprefix == '.'))) {
|
||||
if (!strcmp(sdirs, "yes") || !strcmp(sdirs, "true") ||
|
||||
!strcmp(sdirs, "on") || !strcmp(sdirs, "1"))
|
||||
add = 2;
|
||||
else if (!strcmp(sdirs, ".."))
|
||||
add = 1;
|
||||
|
|
@ -3350,10 +3383,62 @@ cfp_add_sdirs(LinkList final, LinkList orig, char *skipped, char *sdirs)
|
|||
char *s2 = (add == 2 ? dyncat(skipped, ".") : NULL), *m;
|
||||
|
||||
for (node = firstnode(orig); node; incnode(node)) {
|
||||
if (*(m = (char *) getdata(node))) {
|
||||
addlinknode(final, dyncat((char *) getdata(node), s1));
|
||||
if ((m = (char *) getdata(node))) {
|
||||
addlinknode(final, dyncat(m, s1));
|
||||
if (s2)
|
||||
addlinknode(final, dyncat((char *) getdata(node), s2));
|
||||
addlinknode(final, dyncat(m, s2));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fake && *fake) {
|
||||
LinkNode node;
|
||||
char *m, *f, *p, *t, *a, c;
|
||||
int sl = strlen(skipped) + 1;
|
||||
struct stat st1, st2;
|
||||
|
||||
for (; (f = *fake); fake++) {
|
||||
f = dupstring(f);
|
||||
for (p = t = f; *p; p++) {
|
||||
if (*p == ':')
|
||||
break;
|
||||
else if (*p == '\\' && p[1])
|
||||
p++;
|
||||
*t++ = *p;
|
||||
}
|
||||
if (*p) {
|
||||
*t = *p++ = '\0';
|
||||
if (!*p)
|
||||
continue;
|
||||
|
||||
for (node = firstnode(orig); node; incnode(node)) {
|
||||
if ((m = (char *) getdata(node)) &&
|
||||
(!strcmp(f, m) ||
|
||||
(!stat(f, &st1) && !stat((*m ? m : "."), &st2) &&
|
||||
st1.st_dev == st2.st_dev &&
|
||||
st1.st_ino == st2.st_ino))) {
|
||||
while (*p) {
|
||||
while (*p && inblank(*p))
|
||||
p++;
|
||||
if (!*p)
|
||||
break;
|
||||
for (f = t = p; *p; p++) {
|
||||
if (inblank(*p))
|
||||
break;
|
||||
else if (*p == '\\' && p[1])
|
||||
p++;
|
||||
*t++ = *p;
|
||||
}
|
||||
c = *t;
|
||||
*t = '\0';
|
||||
a = (char *) zhalloc(strlen(m) + sl + strlen(f));
|
||||
strcpy(a, m);
|
||||
strcat(a, skipped);
|
||||
strcat(a, f);
|
||||
addlinknode(final, a);
|
||||
*t = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3361,14 +3446,14 @@ cfp_add_sdirs(LinkList final, LinkList orig, char *skipped, char *sdirs)
|
|||
}
|
||||
|
||||
static LinkList
|
||||
cf_pats(int dirs, int noopt, LinkList names, char *skipped, char *matcher,
|
||||
char *sdirs, char **pats)
|
||||
cf_pats(int dirs, int noopt, LinkList names, char **accept, char *skipped,
|
||||
char *matcher, char *sdirs, char **fake, char **pats)
|
||||
{
|
||||
LinkList ret;
|
||||
char *dpats[2];
|
||||
|
||||
if (dirs && (ret = cfp_test_exact(names, skipped)))
|
||||
return cfp_add_sdirs(ret, names, skipped, sdirs);
|
||||
if ((ret = cfp_test_exact(names, accept, skipped)))
|
||||
return cfp_add_sdirs(ret, names, skipped, sdirs, fake);
|
||||
|
||||
if (dirs) {
|
||||
dpats[0] = "*(-/)";
|
||||
|
|
@ -3379,7 +3464,7 @@ cf_pats(int dirs, int noopt, LinkList names, char *skipped, char *matcher,
|
|||
cfp_opt_pats(pats, matcher);
|
||||
|
||||
return cfp_add_sdirs(cfp_bld_pats(dirs, names, skipped, pats),
|
||||
names, skipped, sdirs);
|
||||
names, skipped, sdirs, fake);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -3421,6 +3506,61 @@ cf_ignore(char **names, LinkList ign, char *style, char *path)
|
|||
}
|
||||
}
|
||||
|
||||
static LinkList
|
||||
cf_remove_other(char **names, char *pre, int *amb)
|
||||
{
|
||||
char *p;
|
||||
|
||||
if ((p = strchr(pre, '/'))) {
|
||||
char **n;
|
||||
|
||||
*p = '\0';
|
||||
pre = dyncat(pre, "/");
|
||||
*p = '/';
|
||||
|
||||
for (n = names; *n; n++)
|
||||
if (strpfx(pre, *n))
|
||||
break;
|
||||
|
||||
if (*n) {
|
||||
LinkList ret = newlinklist();
|
||||
|
||||
for (; *names; names++)
|
||||
if (strpfx(pre, *names))
|
||||
addlinknode(ret, dupstring(*names));
|
||||
|
||||
*amb = 0;
|
||||
|
||||
return ret;
|
||||
} else {
|
||||
if (!(p = *names++))
|
||||
*amb = 0;
|
||||
else {
|
||||
char *q;
|
||||
|
||||
if ((q = strchr((p = dupstring(p)), '/')))
|
||||
*q = '\0';
|
||||
|
||||
for (; *names; names++)
|
||||
if (!strpfx(p, *names)) {
|
||||
*amb = 1;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!(p = *names++))
|
||||
*amb = 0;
|
||||
else
|
||||
for (; *names; names++)
|
||||
if (strcmp(p, *names)) {
|
||||
*amb = 1;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
bin_compfiles(char *nam, char **args, char *ops, int func)
|
||||
{
|
||||
|
|
@ -3438,8 +3578,8 @@ bin_compfiles(char *nam, char **args, char *ops, int func)
|
|||
char **tmp;
|
||||
LinkList l;
|
||||
|
||||
if (!args[1] || !args[2] || !args[3] || !args[4] ||
|
||||
(args[0][1] == 'p' && !args[5])) {
|
||||
if (!args[1] || !args[2] || !args[3] || !args[4] || !args[5] ||
|
||||
!args[6] || (args[0][1] == 'p' && !args[7])) {
|
||||
zwarnnam(nam, "too few arguments", NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -3450,8 +3590,9 @@ bin_compfiles(char *nam, char **args, char *ops, int func)
|
|||
for (l = newlinklist(); *tmp; tmp++)
|
||||
addlinknode(l, *tmp);
|
||||
set_list_array(args[1], cf_pats((args[0][1] == 'P'), !!args[0][2],
|
||||
l, args[2], args[3], args[4],
|
||||
args + 5));
|
||||
l, getaparam(args[2]), args[3],
|
||||
args[4], args[5],
|
||||
getaparam(args[6]), args + 7));
|
||||
return 0;
|
||||
}
|
||||
case 'i':
|
||||
|
|
@ -3483,6 +3624,28 @@ bin_compfiles(char *nam, char **args, char *ops, int func)
|
|||
set_list_array(args[2], l);
|
||||
return 0;
|
||||
}
|
||||
case 'r':
|
||||
{
|
||||
char **tmp;
|
||||
LinkList l;
|
||||
int ret = 0;
|
||||
|
||||
if (!args[1] || !args[2]) {
|
||||
zwarnnam(nam, "too few arguments", NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
if (args[3]) {
|
||||
zwarnnam(nam, "too many arguments", NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
if (!(tmp = getaparam(args[1]))) {
|
||||
zwarnnam(nam, "unknown parameter: %s", args[1], 0);
|
||||
return 0;
|
||||
}
|
||||
if ((l = cf_remove_other(tmp, args[2], &ret)))
|
||||
set_list_array(args[1], l);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
zwarnnam(nam, "invalid option: %s", *args, 0);
|
||||
return 1;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue