summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--Completion/Core/_path_files11
-rw-r--r--Src/Zle/complete.c29
-rw-r--r--Src/Zle/compmatch.c2
-rw-r--r--Src/Zle/computil.c194
5 files changed, 204 insertions, 40 deletions
diff --git a/ChangeLog b/ChangeLog
index 90fe5e90e..d3b455a80 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2000-06-13  Sven Wischnowsky  <wischnow@zsh.org>
+
+	* ?????: Completion/Core/_path_files, Src/Zle/complete.c,
+ 	Src/Zle/compmatch.c, Src/Zle/computil.c: fixes for calling
+	compfiles, for completing words with special characters; make
+	compfiles optimisations work with globcomplete and simple match
+	specs
+
 2000-06-12  Peter Stephenson  <pws@cambridgesiliconradio.com>
 
 	* 11867: Src/builtin.c, Src/params.c, Src/zsh.h,
diff --git a/Completion/Core/_path_files b/Completion/Core/_path_files
index 5673e7c4a..7f6f83184 100644
--- a/Completion/Core/_path_files
+++ b/Completion/Core/_path_files
@@ -5,7 +5,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
+local pats haspats ignore pfxsfx sopt gopt opt sdirs ignpar cfopt
 local nm=$compstate[nmatches] menu matcher mopts sort match mid
 
 typeset -U prepaths exppaths
@@ -185,6 +185,7 @@ eorig="$orig"
 [[ $compstate[insert] = (*menu|[0-9]*) || -n "$_comp_correct" ||
    ( -n "$compstate[pattern_match]" &&
      "${orig#\~}" != (|*[^\\])[][*?#~^\|\<\>]* ) ]] && menu=yes
+[[ -n "$_comp_correct" ]] && cfopt=-
 
 # Now let's have a closer look at the string to complete.
 
@@ -222,7 +223,7 @@ if [[ "$pre[1]" = \~ && -z "$compstate[quote]" ]]; then
     elif [[ tmp -le $#dirstack ]]; then
       realpath=$dirstack[tmp]/
     else
-      _message 'not directory stack entries'
+      _message 'not enough directory stack entries'
       return 1
     fi
   elif [[ "$linepath" = [-+] ]]; then
@@ -313,11 +314,11 @@ for prepath in "$prepaths[@]"; do
     # Get the matching files by globbing.
 
     if [[ "$tpre$tsuf" = */* ]]; then
-      compfiles -P tmp1 "$skipped" "$_matcher" "$sdirs"
+      compfiles -P$cfopt tmp1 "$skipped" "$_matcher" "$sdirs"
     elif [[ "$sopt" = *[/f]* ]]; then
-      compfiles -p tmp1 "$skipped" "$_matcher" "$sdirs" "$pats"
+      compfiles -p$cfopt tmp1 "$skipped" "$_matcher" "$sdirs" "$pats[@]"
     else
-      compfiles -p tmp1 "$skipped" "$_matcher" '' "$pats"
+      compfiles -p$cfopt tmp1 "$skipped" "$_matcher" '' "$pats[@]"
     fi
     tmp1=( $~tmp1 )
 
diff --git a/Src/Zle/complete.c b/Src/Zle/complete.c
index 1a659f781..11f6d24ef 100644
--- a/Src/Zle/complete.c
+++ b/Src/Zle/complete.c
@@ -204,16 +204,20 @@ parse_cmatcher(char *name, char *s)
 	case 'R': fl = CMF_RIGHT | CMF_LINE; break;
 	case 'M': fl = CMF_LINE; break;
 	default:
-	    zwarnnam(name, "unknown match specification character `%c'", NULL, *s);
+	    if (name)
+		zwarnnam(name, "unknown match specification character `%c'",
+			 NULL, *s);
 	    return pcm_err;
 	}
 	if (s[1] != ':') {
-	    zwarnnam(name, "missing `:'", NULL, 0);
+	    if (name)
+		zwarnnam(name, "missing `:'", NULL, 0);
 	    return pcm_err;
 	}
 	s += 2;
 	if (!*s) {
-	    zwarnnam(name, "missing patterns", NULL, 0);
+	    if (name)
+		zwarnnam(name, "missing patterns", NULL, 0);
 	    return pcm_err;
 	}
 	if (fl & CMF_LEFT) {
@@ -225,7 +229,8 @@ parse_cmatcher(char *name, char *s)
 		s++;
 
 	    if (!*s || !*++s) {
-		zwarnnam(name, "missing line pattern", NULL, 0);
+		if (name)
+		    zwarnnam(name, "missing line pattern", NULL, 0);
 		return pcm_err;
 	    }
 	} else
@@ -242,10 +247,12 @@ parse_cmatcher(char *name, char *s)
 	    ll = 0;
 	}
 	if ((fl & CMF_RIGHT) && (!*s || !*++s)) {
-	    zwarnnam(name, "missing right anchor", NULL, 0);
+	    if (name)
+		zwarnnam(name, "missing right anchor", NULL, 0);
 	} else if (!(fl & CMF_RIGHT)) {
 	    if (!*s) {
-		zwarnnam(name, "missing word pattern", NULL, 0);
+		if (name)
+		    zwarnnam(name, "missing word pattern", NULL, 0);
 		return pcm_err;
 	    }
 	    s++;
@@ -262,7 +269,8 @@ parse_cmatcher(char *name, char *s)
 	    if (err)
 		return pcm_err;
 	    if (!*s) {
-		zwarnnam(name, "missing word pattern", NULL, 0);
+		if (name)
+		    zwarnnam(name, "missing word pattern", NULL, 0);
 		return pcm_err;
 	    }
 	    s++;
@@ -271,7 +279,8 @@ parse_cmatcher(char *name, char *s)
 
 	if (*s == '*') {
 	    if (!(fl & (CMF_LEFT | CMF_RIGHT))) {
-		zwarnnam(name, "need anchor for `*'", NULL, 0);
+		if (name)
+		    zwarnnam(name, "need anchor for `*'", NULL, 0);
 		return pcm_err;
 	    }
 	    word = NULL;
@@ -284,7 +293,9 @@ parse_cmatcher(char *name, char *s)
 	    word = parse_pattern(name, &s, &wl, 0, &err);
 
 	    if (!word && !line) {
-		zwarnnam(name, "need non-empty word or line pattern", NULL, 0);
+		if (name)
+		    zwarnnam(name, "need non-empty word or line pattern",
+			     NULL, 0);
 		return pcm_err;
 	    }
 	}
diff --git a/Src/Zle/compmatch.c b/Src/Zle/compmatch.c
index 4671b9583..8cdfddede 100644
--- a/Src/Zle/compmatch.c
+++ b/Src/Zle/compmatch.c
@@ -1029,7 +1029,7 @@ comp_match(char *pfx, char *sfx, char *w, Patprog cp, Cline *clp, int qu,
  * corresponding character. */
 
 /**/
-static int
+mod_export int
 pattern_match(Cpattern p, char *s, unsigned char *in, unsigned char *out)
 {
     unsigned char c;
diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c
index ecb7ca3e1..d32f77a1c 100644
--- a/Src/Zle/computil.c
+++ b/Src/Zle/computil.c
@@ -3059,27 +3059,164 @@ cfp_test_exact(LinkList names, char *skipped)
     return (found ? ret : NULL);
 }
 
+static char *
+cfp_matcher_pats(char *matcher, char *add)
+{
+    Cmatcher m = parse_cmatcher(NULL, matcher);
+
+    if (m && m != pcm_err) {
+	char *tmp;
+	int al = strlen(add), tl;
+	VARARR(Cmatcher, ms, al);
+	Cmatcher *mp;
+	Cpattern stopp;
+	int stopl = 0;
+
+	memset(ms, 0, al * sizeof(Cmatcher));
+
+	for (; m && *add; m = m->next) {
+	    stopp = NULL;
+	    if (!(m->flags & (CMF_LEFT|CMF_RIGHT))) {
+		if (m->llen == 1 && m->wlen == 1) {
+		    for (tmp = add, tl = al, mp = ms; tl; tl--, tmp++, mp++) {
+			if (pattern_match(m->line, tmp, NULL, NULL)) {
+			    if (*mp) {
+				*tmp = '\0';
+				al = tmp - add;
+				break;
+			    } else
+				*mp = m;
+			}
+		    }
+		} else {
+		    stopp = m->line;
+		    stopl = m->llen;
+		}
+	    } else if (m->flags & CMF_RIGHT) {
+		if (m->wlen < 0 && !m->llen && m->ralen == 1) {
+		    for (tmp = add, tl = al, mp = ms; tl; tl--, tmp++, mp++) {
+			if (pattern_match(m->right, tmp, NULL, NULL)) {
+			    if (*mp) {
+				*tmp = '\0';
+				al = tmp - add;
+				break;
+			    } else
+				*mp = m;
+			}
+		    }
+		} else if (m->llen) {
+		    stopp = m->line;
+		    stopl = m->llen;
+		} else {
+		    stopp = m->right;
+		    stopl = m->ralen;
+		}
+	    } else {
+		if (!m->lalen)
+		    return "";
+
+		stopp = m->left;
+		stopl = m->lalen;
+	    }
+	    if (stopp)
+		for (tmp = add, tl = al; tl >= stopl; tl--, tmp++)
+		    if (pattern_match(stopp, tmp, NULL, NULL)) {
+			*tmp = '\0';
+			al = tmp - add;
+			break;
+		    }
+	}
+	if (*add) {
+	    char *ret = "", buf[259];
+
+	    for (mp = ms; *add; add++, mp++) {
+		if (!(m = *mp)) {
+		    buf[0] = *add;
+		    buf[1] = '\0';
+		} else if (m->flags & CMF_RIGHT) {
+		    buf[0] = '*';
+		    buf[1] = *add;
+		    buf[2] = '\0';
+		} else {
+		    unsigned char *t, c;
+		    char *p = buf;
+		    int i;
+
+		    for (i = 256, t = m->word->tab; i--; t++)
+			if (*t)
+			    break;
+		    if (i) {
+			t = m->word->tab;
+			*p++ = '[';
+			if (m->line->equiv && m->word->equiv) {
+			    *p++ = *add;
+			    c = m->line->tab[STOUC(*add)];
+			    for (i = 0; i < 256; i++)
+				if (m->word->tab[i] == c) {
+				    *p++ = (char) i;
+				    break;
+				}
+			} else {
+			    if (*add == ']' || t[STOUC(']')])
+				*p++ = ']';
+			    for (i = 0; i < 256; i++, t++)
+				if (*t && ((char) i) != *add &&
+				    i != ']' && i != '-' &&
+				    i != '^' && i != '!')
+				    *p++ = (char) i;
+			    *p++ = *add;
+			    t = m->word->tab;
+			    if (*add != '^' && t[STOUC('^')])
+				*p++ = '^';
+			    if (*add != '!' && t[STOUC('!')])
+				*p++ = '!';
+			    if (*add != '-' && t[STOUC('-')])
+				*p++ = '-';
+			}
+			*p++ = ']';
+			*p = '\0';
+		    } else {
+			*p = '?';
+			p[1] = '\0';
+		    }
+		}
+		ret = dyncat(ret, buf);
+	    }
+	    return ret;
+	}
+    }
+    return add;
+}
+
 static void
 cfp_opt_pats(char **pats, char *matcher)
 {
     char *add, **p, *q, *t, *s;
 
-    /**** For now we don't try to improve the patterns if there are match
-     *    specs. We should work on this some more...
-     *
-     *    And another one: we can do this with comppatmatch if the word
-     *    doesn't contain wildcards, unless the approximate matcher is
-     *    active. Better: unless there is a compadd function. I.e., we
-     *    need one more piece of information from the shell code, at least
-     *    I'd prefer to get it from _path_files in case we find other
-     *    conditions for not trying to improve patterns. */
-
-    if ((comppatmatch && *comppatmatch) || *matcher ||
-	!compprefix || !*compprefix)
+    if (!compprefix || !*compprefix)
 	return;
 
-    add = rembslash(compprefix);
-
+    if (comppatmatch && *comppatmatch) {
+	tokenize(t = rembslash(dyncat(compprefix, compsuffix)));
+	remnulargs(t);
+	if (haswilds(t))
+	    return;
+    }
+    add = (char *) zhalloc(sizeof(compprefix) * 2 + 1);
+    for (s = compprefix, t = add; *s; s++) {
+	if (*s != '\\' || !s[1] || s[1] == '*' || s[1] == '?' ||
+	    s[1] == '<' || s[1] == '>' || s[1] == '(' || s[1] == ')' ||
+	    s[1] == '[' || s[1] == ']' || s[1] == '|' || s[1] == '#' ||
+	    s[1] == '^' || s[1] == '~') {
+	    if ((s == compprefix || s[-1] != '\\') &&
+		(*s == '*' || *s == '?' || *s == '<' || *s == '>' ||
+		 *s == '(' || *s == ')' || *s == '[' || *s == ']' ||
+		 *s == '|' || *s == '#' || *s == '^' || *s == '~'))
+		*t++ = '\\';
+	    *t++ = *s;
+	}
+    }
+    *t = '\0';
     for (p = pats; *add && (q = *p); p++) {
 	if (*q) {
 	    q = dupstring(q);
@@ -3124,6 +3261,9 @@ cfp_opt_pats(char **pats, char *matcher)
 	}
     }
     if (*add) {
+	if (*matcher && !(add = cfp_matcher_pats(matcher, add)))
+	    return;
+
 	for (p = pats; *p; p++)
 	    if (**p == '*')
 		*p = dyncat(add, *p);
@@ -3189,8 +3329,8 @@ cfp_add_sdirs(LinkList final, LinkList orig, char *skipped, char *sdirs)
 }
 
 static LinkList
-cf_pats(int dirs, LinkList names, char *skipped, char *matcher, char *sdirs,
-	char **pats)
+cf_pats(int dirs, int noopt, LinkList names, char *skipped, char *matcher,
+	char *sdirs, char **pats)
 {
     LinkList ret;
     char *dpats[2];
@@ -3203,7 +3343,8 @@ cf_pats(int dirs, LinkList names, char *skipped, char *matcher, char *sdirs,
 	dpats[1] = NULL;
 	pats = dpats;
     }
-    cfp_opt_pats(pats, matcher);
+    if (!noopt)
+	cfp_opt_pats(pats, matcher);
 
     return cfp_add_sdirs(cfp_bld_pats(dirs, names, skipped, pats),
 			 names, skipped, sdirs);
@@ -3255,14 +3396,13 @@ bin_compfiles(char *nam, char **args, char *ops, int func)
 	zwarnnam(nam, "missing option: %s", *args, 0);
 	return 1;
     }
-    if (args[0][2]) {
-	zwarnnam(nam, "invalid option: %s", *args, 0);
-	return 1;
-    }
     switch (args[0][1]) {
     case 'p':
     case 'P':
-	{
+	if (args[0][2] && (args[0][2] != '-' || args[0][3])) {
+	    zwarnnam(nam, "invalid option: %s", *args, 0);
+	    return 1;
+	} else {
 	    char **tmp;
 	    LinkList l;
 
@@ -3277,12 +3417,16 @@ 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'), l, args[2],
-					    args[3], args[4], args + 5));
+	    set_list_array(args[1], cf_pats((args[0][1] == 'P'), !!args[0][2],
+					    l, args[2], args[3], args[4],
+					    args + 5));
 	    return 0;
 	}
     case 'i':
-	{
+	if (args[0][2]) {
+	    zwarnnam(nam, "invalid option: %s", *args, 0);
+	    return 1;
+	} else {
 	    char **tmp;
 	    LinkList l;