1
0
Fork 0
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:
Sven Wischnowsky 2000-06-19 09:32:30 +00:00
parent 207758992a
commit 2769b19881
5 changed files with 233 additions and 54 deletions

View file

@ -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

View file

@ -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%%/*}"

View file

@ -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)

View file

@ -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);

View file

@ -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;