summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--Completion/Core/_path_files58
-rw-r--r--Doc/Zsh/compsys.yo18
-rw-r--r--Src/Zle/compcore.c4
-rw-r--r--Src/Zle/computil.c203
5 files changed, 233 insertions, 54 deletions
diff --git a/ChangeLog b/ChangeLog
index 7d5eb22b2..18c8fe9c2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/Completion/Core/_path_files b/Completion/Core/_path_files
index 7f6f83184..250f6c750 100644
--- a/Completion/Core/_path_files
+++ b/Completion/Core/_path_files
@@ -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 -eq 0 ]]; then
- tmp1=( "$tmp2[@]" )
- compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp2:t}"
- fi
- else
- if [[ "$tmp1[1]" = */* ]]; then
+ 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}"
+ fi
else
- tmp2=( '' )
+ tmp2=( "$tmp1[@]" )
+ compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp1:t}"
fi
-
- compadd -D tmp1 -F _comp_ignore "$matcher[@]" - "${(@)tmp1:t}"
+ else
+ 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%%/*}"
diff --git a/Doc/Zsh/compsys.yo b/Doc/Zsh/compsys.yo
index 82a9fd5fe..2afd505fc 100644
--- a/Doc/Zsh/compsys.yo
+++ b/Doc/Zsh/compsys.yo
@@ -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)
diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c
index 7497d03b4..62d63000a 100644
--- a/Src/Zle/compcore.c
+++ b/Src/Zle/compcore.c
@@ -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);
diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c
index 51a1f61aa..3955ed69d 100644
--- a/Src/Zle/computil.c
+++ b/Src/Zle/computil.c
@@ -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;