zsh-workers
 help / color / mirror / code / Atom feed
* Re: PATCH: matching in the new completion system
  1999-04-26 13:39 PATCH: matching in the new completion system Sven Wischnowsky
@ 1999-04-26 13:25 ` Peter Stephenson
  1999-04-28  4:37 ` Bart Schaefer
  1 sibling, 0 replies; 15+ messages in thread
From: Peter Stephenson @ 1999-04-26 13:25 UTC (permalink / raw)
  To: zsh-workers

Sven Wischnowsky wrote:
> `compadd'
> `-D'

Actually, this fits in with something I had wondered about doing in shell
code (except I was working on setting the n'th element to '' instead of
deleting it entirely), but couldn't work out how to, and I might have even
suggested it for compadd if my brain had had a higher wattage.  It seems a
neat and fast way round.

-- 
Peter Stephenson <pws@ibmth.df.unipi.it>       Tel: +39 050 844536
WWW:  http://www.ifh.de/~pws/
Dipartimento di Fisica, Via Buonarroti 2, 56127 Pisa, Italy


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: PATCH: matching in the new completion system
@ 1999-04-26 13:39 Sven Wischnowsky
  1999-04-26 13:25 ` Peter Stephenson
  1999-04-28  4:37 ` Bart Schaefer
  0 siblings, 2 replies; 15+ messages in thread
From: Sven Wischnowsky @ 1999-04-26 13:39 UTC (permalink / raw)
  To: zsh-workers


About the problem that completion functions might use `compadd -[OA]'
to test for matching strings but may need to do some parameter magic
to remove the unmatched strings from a set of possible completions (if 
only parts of the strings have been tested with `compadd'),

Peter Stephenson wrote:

> I was thinking about having compadd prepare the final list, i.e. you
> give it a list of prefixes and maybe suffixes when you use the -O option so
> that you don't have to do any filtering on the pattern later on.  But at
> the moment it doesn't seem to be necessary.

As I already said, I'd like to have a solution where one can give the
possible completions unaltered to `compadd' and then tell it which
parts of these strings are to be taken as prefixes or suffixes. What
I'm thinking of is an option that says that the strings given with
`-p' and `-s' describe how to take the prefix/suffix from the
words. But the only way to do this I could think of was to give
patterns with `-[ps]' and let the completion code call the matching
code, which wouldn't be any better, since the matching code was what I 
wanted to avoid.

So I searched in a slightly different direction. An optimisation like
this would be interesting to have in cases where we have a list of
strings to give to `compadd' and where we need to get back a list of
matching strings. Now, we can easily add another option, say `-D'
which is a bit like `-[OA]' in that it gets the name of an array as
argument. But instead of just setting this array, it makes `compadd'
use pairs of strings from the words given to it and the elements of
this array. And for every word that couldn't be matched, the
corresponding element in the array is removed (if the n'th word
doesn't match, the n'th element is removed).
All this is a bit like saying `hey, compadd, this is the list of
strings I'm working on (the array) and here are the parts of the
strings you should try to match (the words), modify the list for me'.
Since we will (almost?) always be able to put the possible completions 
in an array, this should be powerful enough for most (or all) cases.

And it's easy to implement, see the patch below (which looks big
mostly because I finally got too annoyed about the ever-growing
argument list of addmatches() and finally put almost everything into a 
struct for it).

So, what do you think? Is this worth including? Should we continue to
search for a better way? Any suggestions?

Bye
 Sven

P.S.:   This was only interesting to have in `_path_files' for now...
P.P.S.: Any better character than `D'? (I thought about `delete', of course.)


diff -u os/Zle/comp.h Src/Zle/comp.h
--- os/Zle/comp.h	Tue Apr 13 09:57:25 1999
+++ Src/Zle/comp.h	Mon Apr 26 15:08:19 1999
@@ -270,6 +270,31 @@
 #define CAF_ALT      4
 #define CAF_MATCH    8
 
+/* Data for compadd and addmatches() */
+
+typedef struct cadata *Cadata;
+
+struct cadata {
+    char *ipre;
+    char *isuf;
+    char *ppre;
+    char *psuf;
+    char *prpre;
+    char *pre;
+    char *suf;
+    char *group;
+    char *rems;
+    char *remf;
+    char *ign;
+    int flags;
+    int aflags;
+    Cmatcher match;
+    char *exp;
+    char *apar;
+    char *opar;
+    char *dpar;
+};
+
 /* Flags for special parameters. */
 
 #define CP_WORDS      (1 <<  0)
diff -u os/Zle/comp1.c Src/Zle/comp1.c
--- os/Zle/comp1.c	Tue Apr 13 10:32:14 1999
+++ Src/Zle/comp1.c	Mon Apr 26 15:08:19 1999
@@ -52,7 +52,7 @@
 /* pointers to functions required by compctl and defined by zle */
 
 /**/
-int (*addmatchesptr) _((char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, int, int, Cmatcher, char *, char *, char *, char **));
+int (*addmatchesptr) _((Cadata, char **));
 
 /**/
 char *(*comp_strptr) _((int *, int *, int));
diff -u os/Zle/compctl.c Src/Zle/compctl.c
--- os/Zle/compctl.c	Tue Apr 13 10:35:14 1999
+++ Src/Zle/compctl.c	Mon Apr 26 15:08:19 1999
@@ -1691,17 +1691,22 @@
 static int
 bin_compadd(char *name, char **argv, char *ops, int func)
 {
-    char *p, **sp, *e;
-    char *ipre = NULL, *isuf = NULL, *ppre = NULL, *psuf = NULL, *prpre = NULL;
-    char *pre = NULL, *suf = NULL, *group = NULL, *m = NULL, *rs = NULL;
-    char *ign = NULL, *rf = NULL, *expl = NULL, *apar = NULL, *opar = NULL;
-    int f = 0, a = CAF_MATCH, dm;
+    struct cadata dat;
+    char *p, **sp, *e, *m;
+    int dm;
     Cmatcher match = NULL;
 
     if (incompfunc != 1) {
 	zerrnam(name, "can only be called from completion function", NULL, 0);
 	return 1;
     }
+    dat.ipre = dat.isuf = dat.ppre = dat.psuf = dat.prpre =
+	dat.pre = dat.suf = dat.group = dat.rems = dat.remf =
+	dat.ign = dat.exp = dat.apar = dat.opar = dat.dpar = NULL;
+    dat.match = NULL;
+    dat.flags = 0;
+    dat.aflags = CAF_MATCH;
+
     for (; *argv && **argv ==  '-'; argv++) {
 	if (!(*argv)[1]) {
 	    argv++;
@@ -1713,64 +1718,64 @@
 	    dm = 0;
 	    switch (*p) {
 	    case 'q':
-		f |= CMF_REMOVE;
+		dat.flags |= CMF_REMOVE;
 		break;
 	    case 'Q':
-		a |= CAF_QUOTE;
+		dat.aflags |= CAF_QUOTE;
 		break;
 	    case 'f':
-		f |= CMF_FILE;
+		dat.flags |= CMF_FILE;
 		break;
 	    case 'F':
-		sp = &ign;
+		sp = &(dat.ign);
 		e = "string expected after -%c";
 		break;
 	    case 'n':
-		f |= CMF_NOLIST;
+		dat.flags |= CMF_NOLIST;
 		break;
 	    case 'U':
-		a &= ~CAF_MATCH;
+		dat.aflags &= ~CAF_MATCH;
 		break;
 	    case 'P':
-		sp = &pre;
+		sp = &(dat.pre);
 		e = "string expected after -%c";
 		break;
 	    case 'S':
-		sp = &suf;
+		sp = &(dat.suf);
 		e = "string expected after -%c";
 		break;
 	    case 'J':
-		sp = &group;
+		sp = &(dat.group);
 		e = "group name expected after -%c";
 		break;
 	    case 'V':
-		if (!group)
-		    a |= CAF_NOSORT;
-		sp = &group;
+		if (!dat.group)
+		    dat.aflags |= CAF_NOSORT;
+		sp = &(dat.group);
 		e = "group name expected after -%c";
 		break;
 	    case 'i':
-		sp = &ipre;
+		sp = &(dat.ipre);
 		e = "string expected after -%c";
 		break;
 	    case 'I':
-		sp = &isuf;
+		sp = &(dat.isuf);
 		e = "string expected after -%c";
 		break;
 	    case 'p':
-		sp = &ppre;
+		sp = &(dat.ppre);
 		e = "string expected after -%c";
 		break;
 	    case 's':
-		sp = &psuf;
+		sp = &(dat.psuf);
 		e = "string expected after -%c";
 		break;
 	    case 'W':
-		sp = &prpre;
+		sp = &(dat.prpre);
 		e = "string expected after -%c";
 		break;
 	    case 'a':
-		a |= CAF_ALT;
+		dat.aflags |= CAF_ALT;
 		break;
 	    case 'M':
 		sp = &m;
@@ -1778,25 +1783,29 @@
 		dm = 1;
 		break;
 	    case 'X':
-		sp = &expl;
+		sp = &(dat.exp);
 		e = "string expected after -%c";
 		break;
 	    case 'r':
-		f |= CMF_REMOVE;
-		sp = &rs;
+		dat.flags |= CMF_REMOVE;
+		sp = &(dat.rems);
 		e = "string expected after -%c";
 		break;
 	    case 'R':
-		f |= CMF_REMOVE;
-		sp = &rf;
+		dat.flags |= CMF_REMOVE;
+		sp = &(dat.remf);
 		e = "function name expected after -%c";
 		break;
 	    case 'A':
-		sp = &apar;
+		sp = &(dat.apar);
 		e = "parameter name expected after -%c";
 		break;
 	    case 'O':
-		sp = &opar;
+		sp = &(dat.opar);
+		e = "parameter name expected after -%c";
+		break;
+	    case 'D':
+		sp = &(dat.dpar);
 		e = "parameter name expected after -%c";
 		break;
 	    case '-':
@@ -1831,11 +1840,10 @@
 	return 1;
 
     match = cpcmatcher(match);
-    a = addmatchesptr(ipre, isuf, ppre, psuf, prpre, pre, suf, group,
-		      rs, rf, ign, f, a, match, expl, apar, opar, argv);
+    dm = addmatchesptr(&dat, argv);
     freecmatcher(match);
 
-    return a;
+    return dm;
 }
 
 #define CVT_RANGENUM 0
diff -u os/Zle/zle_tricky.c Src/Zle/zle_tricky.c
--- os/Zle/zle_tricky.c	Mon Apr 26 10:27:02 1999
+++ Src/Zle/zle_tricky.c	Mon Apr 26 15:08:20 1999
@@ -3472,14 +3472,10 @@
 
 /**/
 int
-addmatches(char *ipre, char *isuf,
-	   char *ppre, char *psuf, char *prpre, char *pre,
-	   char *suf, char *group, char *rems, char *remf, char *ign,
-	   int flags, int aflags, Cmatcher match, char *exp, 
-	   char *apar, char *opar, char **argv)
+addmatches(Cadata dat, char **argv)
 {
     char *s, *ms, *lipre = NULL, *lisuf = NULL, *lpre = NULL, *lsuf = NULL;
-    char **aign = NULL;
+    char **aign = NULL, **dparr;
     int lpl, lsl, pl, sl, bpl, bsl, llpl = 0, llsl = 0, nm = mnum;
     int oisalt = 0, isalt, isexact, doadd;
     Cline lc = NULL;
@@ -3487,45 +3483,52 @@
     struct cmlist mst;
     Cmlist oms = mstack;
     Comp cp = NULL;
-    LinkList aparl = NULL, oparl = NULL;
+    LinkList aparl = NULL, oparl = NULL, dparl = NULL;
 
     /* Switch back to the heap that was used when the completion widget
      * was invoked. */
     SWITCHHEAPS(compheap) {
 	HEAPALLOC {
-	    doadd = (!apar && !opar);
-	    if (apar)
+	    doadd = (!dat->apar && !dat->opar && !dat->dpar);
+	    if (dat->apar)
 		aparl = newlinklist();
-	    if (opar)
+	    if (dat->opar)
 		oparl = newlinklist();
-	    if (exp) {
+	    if (dat->dpar) {
+		if (*(dat->dpar) == '(')
+		    dparr = NULL;
+		else if ((dparr = get_user_var(dat->dpar)) && !*dparr)
+		    dparr = NULL;
+		dparl = newlinklist();
+	    }
+	    if (dat->exp) {
 		expl = (Cexpl) zhalloc(sizeof(struct cexpl));
 		expl->count = expl->fcount = 0;
-		expl->str = dupstring(exp);
+		expl->str = dupstring(dat->exp);
 	    } else
 		expl = NULL;
 
 	    /* Store the matcher in our stack of matchers. */
-	    if (match) {
+	    if (dat->match) {
 		mst.next = mstack;
-		mst.matcher = match;
+		mst.matcher = dat->match;
 		mstack = &mst;
 
 		if (!mnum)
-		    add_bmatchers(match);
+		    add_bmatchers(dat->match);
 
-		addlinknode(matchers, match);
-		match->refc++;
+		addlinknode(matchers, dat->match);
+		dat->match->refc++;
 	    }
 	    if (mnum && (mstack || bmatchers))
 		update_bmatchers();
 
 	    /* Get the suffixes to ignore. */
-	    if (ign)
-		aign = get_user_var(ign);
+	    if (dat->ign)
+		aign = get_user_var(dat->ign);
 	    /* Get the contents of the completion variables if we have
 	     * to perform matching. */
-	    if (aflags & CAF_MATCH) {
+	    if (dat->aflags & CAF_MATCH) {
 		lipre = dupstring(compiprefix);
 		lisuf = dupstring(compisuffix);
 		lpre = dupstring(compprefix);
@@ -3533,8 +3536,8 @@
 		llpl = strlen(lpre);
 		llsl = strlen(lsuf);
 		/* Test if there is an existing -P prefix. */
-		if (pre && *pre) {
-		    pl = pfxlen(pre, lpre);
+		if (dat->pre && *dat->pre) {
+		    pl = pfxlen(dat->pre, lpre);
 		    llpl -= pl;
 		    lpre += pl;
 		}
@@ -3557,79 +3560,76 @@
 		}
 	    }
 	    /* Now duplicate the strings we have from the command line. */
-	    if (ipre)
-		ipre = (lipre ? dyncat(lipre, ipre) : dupstring(ipre));
+	    if (dat->ipre)
+		dat->ipre = (lipre ? dyncat(lipre, dat->ipre) :
+			     dupstring(dat->ipre));
 	    else if (lipre)
-		ipre = lipre;
-	    if (isuf)
-		isuf = (lisuf ? dyncat(lisuf, isuf) : dupstring(isuf));
+		dat->ipre = lipre;
+	    if (dat->isuf)
+		dat->isuf = (lisuf ? dyncat(lisuf, dat->isuf) :
+			     dupstring(dat->isuf));
 	    else if (lisuf)
-		isuf = lisuf;
-	    if (ppre) {
-		ppre = dupstring(ppre);
-		lpl = strlen(ppre);
+		dat->isuf = lisuf;
+	    if (dat->ppre) {
+		dat->ppre = dupstring(dat->ppre);
+		lpl = strlen(dat->ppre);
 	    } else
 		lpl = 0;
-	    if (psuf) {
-		psuf = dupstring(psuf);
-		lsl = strlen(psuf);
+	    if (dat->psuf) {
+		dat->psuf = dupstring(dat->psuf);
+		lsl = strlen(dat->psuf);
 	    } else
 		lsl = 0;
-	    if (aflags & CAF_MATCH) {
-		s = ppre ? ppre : "";
-		if (llpl <= lpl && strpfx(lpre, s)) {
-		    llpl = 0;
+	    if (dat->aflags & CAF_MATCH) {
+		s = dat->ppre ? dat->ppre : "";
+		if (llpl <= lpl && strpfx(lpre, s))
 		    lpre = "";
-		} else if (llpl > lpl && strpfx(s, lpre)) {
-		    llpl -= lpl;
+		else if (llpl > lpl && strpfx(s, lpre))
 		    lpre += lpl;
-		} else
+		else
 		    *argv = NULL;
-		s = psuf ? psuf : "";
-		if (llsl <= lsl && strsfx(lsuf, s)) {
-		    llsl = 0;
+		s = dat->psuf ? dat->psuf : "";
+		if (llsl <= lsl && strsfx(lsuf, s))
 		    lsuf = "";
-		} else if (llsl > lsl && strsfx(s, lsuf)) {
+		else if (llsl > lsl && strsfx(s, lsuf))
 		    lsuf[llsl - lsl] = '\0';
-		    llsl -= lsl;
-		} else
+		else
 		    *argv = NULL;
 	    }
 	    if (*argv) {
-		if (pre)
-		    pre = dupstring(pre);
-		if (suf)
-		    suf = dupstring(suf);
-		if (!prpre && (prpre = ppre)) {
-		    singsub(&prpre);
-		    untokenize(prpre);
+		if (dat->pre)
+		    dat->pre = dupstring(dat->pre);
+		if (dat->suf)
+		    dat->suf = dupstring(dat->suf);
+		if (!dat->prpre && (dat->prpre = dat->ppre)) {
+		    singsub(&(dat->prpre));
+		    untokenize(dat->prpre);
 		} else
-		    prpre = dupstring(prpre);
+		    dat->prpre = dupstring(dat->prpre);
 		/* Select the group in which to store the matches. */
-		if (group) {
+		if (dat->group) {
 		    endcmgroup(NULL);
-		    begcmgroup(group, (aflags & CAF_NOSORT));
-		    if (aflags & CAF_NOSORT)
+		    begcmgroup(dat->group, (dat->aflags & CAF_NOSORT));
+		    if (dat->aflags & CAF_NOSORT)
 			mgroup->flags |= CGF_NOSORT;
 		} else {
 		    endcmgroup(NULL);
 		    begcmgroup("default", 0);
 		}
 		/* Select the set of matches. */
-		oisalt = (aflags & CAF_ALT);
+		oisalt = (dat->aflags & CAF_ALT);
 
-		if (remf) {
-		    remf = dupstring(remf);
-		    rems = NULL;
-		} else if (rems)
-		    rems = dupstring(rems);
+		if (dat->remf) {
+		    dat->remf = dupstring(dat->remf);
+		    dat->rems = NULL;
+		} else if (dat->rems)
+		    dat->rems = dupstring(dat->rems);
 
 		/* Probably quote the prefix and suffix for testing. */
-		if (!cp && (aflags & CAF_MATCH) && !(aflags & CAF_QUOTE)) {
+		if (!cp && (dat->aflags & CAF_MATCH) &&
+		    !(dat->aflags & CAF_QUOTE)) {
 		    lpre = quotename(lpre, NULL);
 		    lsuf = quotename(lsuf, NULL);
-		    llpl = strlen(lpre);
-		    llsl = strlen(lsuf);
 		}
 	    }
 	    /* Walk through the matches given. */
@@ -3638,7 +3638,7 @@
 		bpl = brpl;
 		bsl = brsl;
 		isalt = oisalt;
-		if ((!psuf || !*psuf) && aign) {
+		if ((!dat->psuf || !*(dat->psuf)) && aign) {
 		    /* Do the suffix-test. If the match has one of the
 		     * suffixes from ign, we put it in the alternate set. */
 		    char **pt = aign;
@@ -3649,39 +3649,52 @@
 			    && !strcmp(*pt, s + sl - filell))
 			    isalt = 1;
 
-		    if (isalt && !doadd)
+		    if (isalt && !doadd) {
+			if (dparr && !*++dparr)
+			    dparr = NULL;
 			continue;
+		    }
 		}
-		if (!(aflags & CAF_MATCH)) {
+		if (!(dat->aflags & CAF_MATCH)) {
 		    ms = dupstring(s);
 		    lc = bld_parts(ms, sl, -1, NULL);
 		    isexact = 0;
 		} else if (!(ms = comp_match(lpre, lsuf, s, cp, &lc,
-					     !(aflags & CAF_QUOTE),
-					     &bpl, &bsl, &isexact)))
+					     !(dat->aflags & CAF_QUOTE),
+					     &bpl, &bsl, &isexact))) {
+		    if (dparr && !*++dparr)
+			dparr = NULL;
 		    continue;
-
+		}
 		if (doadd) {
-		    cm = add_match_data(isalt, ms, lc, ipre, ipre, isuf, pre, 
-					prpre, ppre, psuf, suf, bpl, bsl,
-					flags, isexact);
-		    cm->rems = rems;
-		    cm->remf = remf;
+		    cm = add_match_data(isalt, ms, lc, dat->ipre, dat->ipre,
+					dat->isuf, dat->pre, dat->prpre,
+					dat->ppre, dat->psuf, dat->suf,
+					bpl, bsl, dat->flags, isexact);
+		    cm->rems = dat->rems;
+		    cm->remf = dat->remf;
 		} else {
-		    if (apar)
+		    if (dat->apar)
 			addlinknode(aparl, ms);
-		    if (opar)
+		    if (dat->opar)
 			addlinknode(oparl, s);
+		    if (dat->dpar && dparr) {
+			addlinknode(dparl, *dparr);
+			if (!*++dparr)
+			    dparr = NULL;
+		    }
 		    free_cline(lc);
 		}
 	    }
 	    compnmatches = mnum;
-	    if (exp)
+	    if (dat->exp)
 		addexpl();
-	    if (apar)
-		set_param(apar, aparl);
-	    if (opar)
-		set_param(opar, oparl);
+	    if (dat->apar)
+		set_param(dat->apar, aparl);
+	    if (dat->opar)
+		set_param(dat->opar, oparl);
+	    if (dat->dpar)
+		set_param(dat->dpar, dparl);
 	} LASTALLOC;
     } SWITCHBACKHEAPS;
 
diff -u od/Zsh/compwid.yo Doc/Zsh/compwid.yo
--- od/Zsh/compwid.yo	Fri Apr 23 13:38:41 1999
+++ Doc/Zsh/compwid.yo	Mon Apr 26 15:08:21 1999
@@ -340,7 +340,7 @@
 xitem([ tt(-J) var(name) ] [ tt(-V) var(name) ] [ tt(-X) var(explanation) ])
 xitem([ tt(-r) var(remove-chars) ] [ tt(-R) var(remove-func) ])
 xitem([ tt(-M) var(match-spec) ] [ tt(-O) var(array) ] [ tt(-A) var(array) ])
-item([ tt(--) ] [ var(words) ... ])(
+item([ tt(-D) var(array) ] [ tt(--) ] [ var(words) ... ])(
 
 This builtin command can be used to add matches directly and control
 all the information the completion code stores with each possible
@@ -517,6 +517,13 @@
 on the command line and the string `tt(foo)' as one of the var(words), this
 option stores the string `tt(nofoo)' in the array, whereas the tt(-O)
 option stores the `tt(foo)' originally given.
+)
+item(tt(-D) var(array))(
+As with tt(-O), the var(words) are not added to the set of possible
+completions. Instead, the completion code tests every var(word) if 
+it matches what is on the line. If the var(n)'th var(word) does not
+match, the var(n)'th element of the var(array) is removed. Elements
+for which the corresponding var(word) is matched are retained.
 )
 item(tt(-), tt(--))(
 This flag ends the list of flags and options. All arguments after it
diff -u oc/Core/_multi_parts Completion/Core/_multi_parts
--- oc/Core/_multi_parts	Tue Apr 13 10:32:15 1999
+++ Completion/Core/_multi_parts	Mon Apr 26 15:08:20 1999
@@ -83,8 +83,7 @@
   else
     # No exact match, see how many strings match what's on the line.
 
-    tmp2=( "${(@)matches%%${sep}*}" )
-    compadd -O tmp1 - "$tmp2[@]"
+    compadd -O tmp1 - "${(@)matches%%${sep}*}"
 
     if [[ $#tmp1 -eq 1 ]]; then
 
diff -u oc/Core/_path_files Completion/Core/_path_files
--- oc/Core/_path_files	Mon Apr 19 10:33:53 1999
+++ Completion/Core/_path_files	Mon Apr 26 15:09:32 1999
@@ -230,14 +230,15 @@
     if [[ -n "$PREFIX$SUFFIX" ]]; then
       # See which of them match what's on the line.
 
-      compadd -O tmp2 "$ignore[@]" - "${(@)tmp1##*/}"
+      tmp2=("$tmp1[@]")
+      compadd -D tmp1 "$ignore[@]" - "${(@)tmp1##*/}"
 
       # If no file matches, save the expanded path and continue with
       # the outer loop.
 
-      if [[ $#tmp2 -eq 0 ]]; then
- 	if [[ "$tmp1[1]" = */* ]]; then
-	  tmp2=( "${(@)tmp1#${prepath}${realpath}}" )
+      if [[ $#tmp1 -eq 0 ]]; then
+ 	if [[ "$tmp2[1]" = */* ]]; then
+	  tmp2=( "${(@)tmp2#${prepath}${realpath}}" )
 	  if [[ "$tmp2[1]" = */* ]]; then
 	    exppaths=( "$exppaths[@]" ${^tmp2%/*}/${tpre}${tsuf} )
           else
@@ -245,14 +246,6 @@
 	  fi
         fi
         continue 2
-      fi
-
-      # Remove all files that weren't matched.
-
-      if [[ "$tmp1[1]" = */* ]]; then
-        tmp1=( "${(@M)tmp1:#*/(${(j:|:)~${(@)tmp2:q}})}" )
-      else
-        tmp1=( "${(@M)tmp1:#(${(j:|:)~${(@)tmp2:q}})}" )
       fi
     elif (( ! $#tmp1 )); then
       continue 2

--
Sven Wischnowsky                         wischnow@informatik.hu-berlin.de


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: PATCH: matching in the new completion system
  1999-04-26 13:39 PATCH: matching in the new completion system Sven Wischnowsky
  1999-04-26 13:25 ` Peter Stephenson
@ 1999-04-28  4:37 ` Bart Schaefer
  1 sibling, 0 replies; 15+ messages in thread
From: Bart Schaefer @ 1999-04-28  4:37 UTC (permalink / raw)
  To: zsh-workers

On Apr 26,  3:39pm, Sven Wischnowsky wrote:
} Subject: Re: PATCH: matching in the new completion system
}
} All this is a bit like saying `hey, compadd, this is the list of
} strings I'm working on (the array) and here are the parts of the
} strings you should try to match (the words), modify the list for me'.

I thought I was following this, until I got to (the words).  Could you
please give an example?

} So, what do you think? Is this worth including? Should we continue to
} search for a better way? Any suggestions?

A mostly-unrelated one:  Now that you have the addmatches() parameters
broken out into a struct, could you attach a comment to each line to
explain what the field represents?

-- 
Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: PATCH: matching in the new completion system
@ 1999-04-28  7:44 Sven Wischnowsky
  0 siblings, 0 replies; 15+ messages in thread
From: Sven Wischnowsky @ 1999-04-28  7:44 UTC (permalink / raw)
  To: zsh-workers


Bart Schaefer wrote:

> On Apr 26,  3:39pm, Sven Wischnowsky wrote:
> } Subject: Re: PATCH: matching in the new completion system
> }
> } All this is a bit like saying `hey, compadd, this is the list of
> } strings I'm working on (the array) and here are the parts of the
> } strings you should try to match (the words), modify the list for me'.
> 
> I thought I was following this, until I got to (the words).  Could you
> please give an example?

I'll describe how this is used in _path_files (praeter propter):

We have an array, say `matches' (in _path_files it has another name,
but...), containing all the possible completions we have collected
until now. Now we need to match only parts of the strings, not the
whole strings. Getting these parts is easy (or at least possible)
using a parameter expansion on `matches'. So, we just do: 

  compadd -D matches - ${matches##*/}

(if the `parts' are pathname components), after setting up PREFIX and
SUFFIX. With that, compadd will modify our list of matches in place and 
we can still use the full power of parameter expansion to describe
what we want to have matched. I /think/ this makes it powerful enough
for most cases: if you collect possible completions, you will use an
array in most cases anyway, and, from another point of view, if you
have a problem where `compadd -D' might be useful, you should always
be able to use an array to take advantage of it.

In fact, this is at least as powerful as the other thing I described
(an option to make -[ps] be taken as descriptions what the prefixes
and suffixes are, which would be given in the words). And it's
easy to implement and fast.

Ok?

> A mostly-unrelated one:  Now that you have the addmatches() parameters
> broken out into a struct, could you attach a comment to each line to
> explain what the field represents?

Oops. I wanted to do that anyway, seems I forgot it in the end.

Bye
 Sven

diff -u os/Zle/comp.h Src/Zle/comp.h
--- os/Zle/comp.h	Tue Apr 27 11:03:33 1999
+++ Src/Zle/comp.h	Wed Apr 28 09:26:51 1999
@@ -275,24 +275,24 @@
 typedef struct cadata *Cadata;
 
 struct cadata {
-    char *ipre;
-    char *isuf;
-    char *ppre;
-    char *psuf;
-    char *prpre;
-    char *pre;
-    char *suf;
-    char *group;
-    char *rems;
-    char *remf;
-    char *ign;
-    int flags;
-    int aflags;
-    Cmatcher match;
-    char *exp;
-    char *apar;
-    char *opar;
-    char *dpar;
+    char *ipre;			/* ignored prefix (-i) */
+    char *isuf;			/* ignored suffix (-I) */
+    char *ppre;			/* `path' prefix (-p) */
+    char *psuf;			/* `path' suffix (-s) */
+    char *prpre;		/* expanded `path' prefix (-W) */
+    char *pre;			/* prefix to insert (-P) */
+    char *suf;			/* suffix to insert (-S) */
+    char *group;		/* name of the group (-[JV]) */
+    char *rems;			/* remove suffix on chars... (-r) */
+    char *remf;			/* function to remove suffix (-R) */
+    char *ign;			/* ignored suffixes (-F) */
+    int flags;			/* CMF_* flags (-[fqn]) */
+    int aflags;			/* CAF_* flags (-[QUa]) */
+    Cmatcher match;		/* match spec (parsed from -M) */
+    char *exp;			/* explanation (-X) */
+    char *apar;			/* array to store matches in (-A) */
+    char *opar;			/* array to store originals in (-O) */
+    char *dpar;			/* array to delete non-matches in (-D) */
 };
 
 /* Flags for special parameters. */

--
Sven Wischnowsky                         wischnow@informatik.hu-berlin.de


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: PATCH: matching in the new completion system
@ 1999-04-14  8:31 Sven Wischnowsky
  0 siblings, 0 replies; 15+ messages in thread
From: Sven Wischnowsky @ 1999-04-14  8:31 UTC (permalink / raw)
  To: zsh-workers


Peter Stephenson wrote:

> I was thinking about having compadd prepare the final list, i.e. you
> give it a list of prefixes and maybe suffixes when you use the -O option so
> that you don't have to do any filtering on the pattern later on.  But at
> the moment it doesn't seem to be necessary.

;-) I was thinking about the same thing when I first implemented the
new `_path_files', but couldn't find a way to give those prefixes and
suffixes to `compadd'. I would prefer to be able to make this by
giving the strings to test plus something, where the something are not 
two more lists of strings. Maybe the strings plus a way to say what
should be compared (since with `-[AO]' compadd is only doing matching,
almost all other options are useless and hence ignored, so it might be 
ok to add support for matching magic here). On the other hand, all
versions of `_path_files' we had make it clear that being able to give 
different `-p' and `-s' prefixes and suffixes per string would be
interesting to have without the `-[AO]', too.

I was also thinking about being able to give an array-name instead of
giving the string as arguments. Might speed things up a bit for large
numbers of strings to test.

Ok, does anyone have suggestions (for the first one)?

Bye
 Sven


--
Sven Wischnowsky                         wischnow@informatik.hu-berlin.de


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: PATCH: matching in the new completion system
  1999-04-14  6:19 Sven Wischnowsky
@ 1999-04-14  7:50 ` Peter Stephenson
  0 siblings, 0 replies; 15+ messages in thread
From: Peter Stephenson @ 1999-04-14  7:50 UTC (permalink / raw)
  To: zsh-workers

Sven Wischnowsky wrote:
> The patch below should make things faster by
> avoiding the pattern matching if the string from the line is empty
> (for the component currently handled).

That seems to remove the problem for all the ordinary things I've tried so
far.  Thanks.

I was thinking about having compadd prepare the final list, i.e. you
give it a list of prefixes and maybe suffixes when you use the -O option so
that you don't have to do any filtering on the pattern later on.  But at
the moment it doesn't seem to be necessary.

> > It does seem to be due to speed.  In fact, it now takes 8 seconds just to
> > build all the files in the Src directory, irrespective of path completion,
> > which should be almost instantaneous.  I smell a rat somewhere.
> 
> Ugh. 8 seconds??? Without xtrace?

Yes, and it's now back to what it was.  Whenever I stopped it with the
debugger, it was evaluating a whole stack (some 100's) of nested
parsecompsw()'s, and always stopped in zhalloc() looking for a free heap.
All the previous ones seemed to be exactly full, which strikes me as a bit
fishy.  Even so, maybe it's worth thinking about having a separate free
list to reduce the search time --- since the blocks are 8k long, it could
be removed from that when there was less than the length of a short string
remaining without wasting too much space.  I'm not using the zsh memory
routines, since they don't work for AIX.

-- 
Peter Stephenson <pws@ibmth.df.unipi.it>       Tel: +39 050 844536
WWW:  http://www.ifh.de/~pws/
Dipartimento di Fisica, Via Buonarroti 2, 56127 Pisa, Italy


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: PATCH: matching in the new completion system
@ 1999-04-14  6:19 Sven Wischnowsky
  1999-04-14  7:50 ` Peter Stephenson
  0 siblings, 1 reply; 15+ messages in thread
From: Sven Wischnowsky @ 1999-04-14  6:19 UTC (permalink / raw)
  To: zsh-workers


Peter Stephenson wrote:

> It's something to with the |'s.  It's trying to build a *huge* pattern like
> that.  By the looks of it, it includes every single thing in the command
> table.  It begins
> 
> */(XNSquery|XNSrouted|acct|adfutil|allocp|arp|audit|auditbin|auditcat|
> auditpr|auditselect|auditstream|automount|autopush|backbyinode|backbyname|
> backup|bffcreate|biod|bootexpand|bootinfo|bootpd|bootrec...
> 
> These are the tail ends of the files in /u*/s*/*. The trace of _path_files
> finishes up with
> 
> + tmp1=( <all the files in /u*/s*/*, this looks reasonable> )
> + compadd -O tmp2 -F fignore - <all the commands from the last part of that>
> + [[ 423 -eq 0 ]]
> + [[ /usr/sbin/XNSquery == */* ]]

I already guessed that. The patch below should make things faster by
avoiding the pattern matching if the string from the line is empty
(for the component currently handled). It also improves the way the
matches are added when there are no path suffixes. Finally, it
re-introduces trying to use `compgen' first, bit slightly more
restrictive than in previous versions: only if we are at the end of
the word from the line. I had removed it because the function wasn't
*that* slow for me and I had found a bug when completion was started
with the cursor in the middle of the word. When the suffix was
expanded by a previous completion and that turned it into an existing
filename, this was accepted immediatly instead of moving the cursor to 
the end and continuing with completion there.

> It does seem to be due to speed.  In fact, it now takes 8 seconds just to
> build all the files in the Src directory, irrespective of path completion,
> which should be almost instantaneous.  I smell a rat somewhere.

Ugh. 8 seconds??? Without xtrace?

Bye
 Sven

diff -u oc/Core/_path_files Completion/Core/_path_files
--- oc/Core/_path_files	Tue Apr 13 15:19:19 1999
+++ Completion/Core/_path_files	Wed Apr 14 08:13:52 1999
@@ -110,6 +110,34 @@
    ( $#compstate[pattern_match] -ne 0 &&
      "${orig#\~}" != "${${orig#\~}:q}" ) ]] && menu=yes
 
+# We will first try normal completion called with `compgen', but only if we
+# weren't given a `-F', `-r', or `-R' option or we are in the string.
+
+if [[ -z "$suf" && $#ignore -eq 0 && $#remsfx -eq 0 &&
+      -z "$_comp_correct" ]]; then
+  # First build an array containing the `-W' option, if there is any and we
+  # want to use it. We don't want to use it if the string from the command line
+  # is a absolute path or relative to the current directory.
+
+  if [[ -z "$prepaths[1]" || "$pre[1]" = [~/] || "$pre" = (.|..)/* ]]; then
+    tmp1=()
+  else
+    tmp1=(-W "( $prepaths )")
+  fi
+
+  # Now call compgen.
+
+  if [[ -z "$gopt" ]]; then
+    compgen "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" "$tmp1[@]" $sopt
+  else
+    compgen "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" "$tmp1[@]" $sopt -g "$pats"
+  fi
+
+  # If this generated any matches, we don't want to do in-path completion.
+
+  [[ compstate[nmatches] -eq nm ]] || return 0
+fi
+
 # If given no `-F' option, we want to use `fignore'.
 
 (( $#ignore )) || ignore=(-F fignore)
@@ -199,24 +227,31 @@
       tmp1=( ${^tmp1}${^~pats} )
     fi
 
-    # See which of them match what's on the line.
+    if [[ -n "$PREFIX$SUFFIX" ]]; then
+      # See which of them match what's on the line.
 
-    compadd -O tmp2 "$ignore[@]" - "${(@)tmp1##*/}"
+      compadd -O tmp2 "$ignore[@]" - "${(@)tmp1##*/}"
 
-    # If no file matches, save the expanded path and continue with
-    # the outer loop.
+      # If no file matches, save the expanded path and continue with
+      # the outer loop.
 
-    if [[ $#tmp2 -eq 0 && "$tmp1[1]" = */* ]]; then
-      exppaths=( "$exppaths[@]" ${^tmp1%/*}/${tpre}${tsuf} )
-      continue 2
-    fi
+      if [[ $#tmp2 -eq 0 ]]; then
+ 	[[ "$tmp1[1]" = */* ]] &&
+	    exppaths=( "$exppaths[@]" ${^tmp1%/*}/${tpre}${tsuf} )
+        continue 2
+      fi
 
-    # Remove all files that weren't matched.
+      # Remove all files that weren't matched.
 
-    if [[ "$tmp1[1]" = */* ]]; then
-      tmp1=( "${(@M)tmp1:#*/(${(j:|:)~${(@)tmp2:q}})}" )
-    else
-      tmp1=( "${(@M)tmp1:#(${(j:|:)~${(@)tmp2:q}})}" )
+      if [[ "$tmp1[1]" = */* ]]; then
+        tmp1=( "${(@M)tmp1:#*/(${(j:|:)~${(@)tmp2:q}})}" )
+      else
+        tmp1=( "${(@M)tmp1:#(${(j:|:)~${(@)tmp2:q}})}" )
+      fi
+    elif (( ! $#tmp1 )); then
+      [[ "$tmp1[1]" = */* ]] &&
+          exppaths=( "$exppaths[@]" ${^tmp1%/*}/${tpre}${tsuf} )
+      continue 2
     fi
 
     # Step over to the next component, if any.
@@ -295,13 +330,11 @@
 		    - "${i%%/*}"
 	  done
         else
-          for i in "$tmp1[@]"; do
-	    compadd -Uf -p "$linepath$testpath" \
-		    -W "$prepath$realpath$testpath" "$ignore[@]" \
-		    "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \
-		    "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
-		    - "$i"
-	  done
+	  compadd -Uf -p "$linepath$testpath" \
+		  -W "$prepath$realpath$testpath" "$ignore[@]" \
+		  "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \
+		  "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
+		  - "$tmp1[@]"
         fi
       fi
       tmp4=-

--
Sven Wischnowsky                         wischnow@informatik.hu-berlin.de


^ permalink raw reply	[flat|nested] 15+ messages in thread

* RE: PATCH: matching in the new completion system
  1999-04-13 14:39 ` Peter Stephenson
@ 1999-04-14  6:15   ` Andrej Borsenkow
  0 siblings, 0 replies; 15+ messages in thread
From: Andrej Borsenkow @ 1999-04-14  6:15 UTC (permalink / raw)
  To: Peter Stephenson, zsh-workers

>
> It does seem to be due to speed.  In fact, it now takes 8 seconds just to
> build all the files in the Src directory, irrespective of path completion,
> which should be almost instantaneous.  I smell a rat somewhere.
>

It works for me O.K. With path completion as well. I must confess, I don't
use ZSH memory management and compile with optimisation (as I currently
don't have any debugger, it makes no difference to me).

/andrej


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: PATCH: matching in the new completion system
  1999-04-13 13:18 Sven Wischnowsky
@ 1999-04-13 14:39 ` Peter Stephenson
  1999-04-14  6:15   ` Andrej Borsenkow
  0 siblings, 1 reply; 15+ messages in thread
From: Peter Stephenson @ 1999-04-13 14:39 UTC (permalink / raw)
  To: zsh-workers

Sven Wischnowsky wrote:
> Peter Stephenson wrote:
> 
> > It gets worse after that.  If I now go back and do /u/s/<TAB>, the whole
> > shell hangs completely and has to be killed from somewhere else.  (I just
> > started off with /u/s/m<TAB>, but it all looks similar.)
> 
> Ick. I can't reproduce this, but...
> 
> Are you sure it hangs? Or is it just incredibly slow? For me, the lack
> of speed comes from the size of the directories `/usr/s*'. Also, there 
> was a problem with building a pattern that is used to remove unmatched 
> strings over which I stumbled when trying the same (`/u/s/<TAB>'). The 
> problem was that I used `${(@M)tmp1:#(${(j:|:)~tmp2})}' where I should
> have used `${(@M)tmp1:#(${(j:|:)~${(@)tmp2:q}})}' to make sure special
> characters in the filenames are not taken as pattern characters.

It's something to with the |'s.  It's trying to build a *huge* pattern like
that.  By the looks of it, it includes every single thing in the command
table.  It begins

*/(XNSquery|XNSrouted|acct|adfutil|allocp|arp|audit|auditbin|auditcat|
auditpr|auditselect|auditstream|automount|autopush|backbyinode|backbyname|
backup|bffcreate|biod|bootexpand|bootinfo|bootpd|bootrec...

These are the tail ends of the files in /u*/s*/*. The trace of _path_files
finishes up with

+ tmp1=( <all the files in /u*/s*/*, this looks reasonable> )
+ compadd -O tmp2 -F fignore - <all the commands from the last part of that>
+ [[ 423 -eq 0 ]]
+ [[ /usr/sbin/XNSquery == */* ]]

and then it stops.  The part it's doing corresponds to

    # Remove all files that weren't matched.

    if [[ "$tmp1[1]" = */* ]]; then
      tmp1=( "${(@M)tmp1:#*/(${(j:|:)~${(@)tmp2:q}})}" )
    else
      tmp1=( "${(@M)tmp1:#(${(j:|:)~${(@)tmp2:q}})}" )
    fi

It does seem to be due to speed.  In fact, it now takes 8 seconds just to
build all the files in the Src directory, irrespective of path completion,
which should be almost instantaneous.  I smell a rat somewhere.

-- 
Peter Stephenson <pws@ibmth.df.unipi.it>       Tel: +39 050 844536
WWW:  http://www.ifh.de/~pws/
Dipartimento di Fisica, Via Buonarroti 2, 56127 Pisa, Italy


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: PATCH: matching in the new completion system
@ 1999-04-13 13:18 Sven Wischnowsky
  1999-04-13 14:39 ` Peter Stephenson
  0 siblings, 1 reply; 15+ messages in thread
From: Sven Wischnowsky @ 1999-04-13 13:18 UTC (permalink / raw)
  To: zsh-workers


Andrej Borsenkow wrote:

> (implying /usr/share/man/mrd)
> 
> bor@itsrm2:/tools/src/zsh-3.1.5-pws-14/Completion%> zsh -f
> itsrm2% fpath=(*(/))
> itsrm2% source Core/compinit 
> bor@itsrm2:~%> l /u/s/m/m<TAB>
> itsrm2% l /usr/s<TAB>
> itsrm2% l /usr/s  
> sadm/    sbin/    share/   spool@   src/     sysadm/  

Certainly not intentional. I forgot to make sure that `compadd' knows
that the strings contain parts separated by slashes.

Peter Stephenson wrote:

> It gets worse after that.  If I now go back and do /u/s/<TAB>, the whole
> shell hangs completely and has to be killed from somewhere else.  (I just
> started off with /u/s/m<TAB>, but it all looks similar.)

Ick. I can't reproduce this, but...

Are you sure it hangs? Or is it just incredibly slow? For me, the lack
of speed comes from the size of the directories `/usr/s*'. Also, there 
was a problem with building a pattern that is used to remove unmatched 
strings over which I stumbled when trying the same (`/u/s/<TAB>'). The 
problem was that I used `${(@M)tmp1:#(${(j:|:)~tmp2})}' where I should
have used `${(@M)tmp1:#(${(j:|:)~${(@)tmp2:q}})}' to make sure special
characters in the filenames are not taken as pattern characters.

Still, I would like to know where it got stuck.

Bye
 Sven

diff -u oc/Core/_path_files Completion/Core/_path_files
--- oc/Core/_path_files	Tue Apr 13 15:10:30 1999
+++ Completion/Core/_path_files	Tue Apr 13 15:09:19 1999
@@ -214,9 +214,9 @@
     # Remove all files that weren't matched.
 
     if [[ "$tmp1[1]" = */* ]]; then
-      tmp1=( "${(@M)tmp1:#*/(${(j:|:)~tmp2})}" )
+      tmp1=( "${(@M)tmp1:#*/(${(j:|:)~${(@)tmp2:q}})}" )
     else
-      tmp1=( "${(@M)tmp1:#(${(j:|:)~tmp2})}" )
+      tmp1=( "${(@M)tmp1:#(${(j:|:)~${(@)tmp2:q}})}" )
     fi
 
     # Step over to the next component, if any.
@@ -290,7 +290,7 @@
           for i in "$tmp1[@]"; do
 	    compadd -Uf -p "$linepath$testpath" -s "/${i#*/}" \
 		    -W "$prepath$realpath$testpath" "$ignore[@]" \
-		    "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \
+		    "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" -M 'r:|/=* r:|=*' \
 		    "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
 		    - "${i%%/*}"
 	  done

--
Sven Wischnowsky                         wischnow@informatik.hu-berlin.de


^ permalink raw reply	[flat|nested] 15+ messages in thread

* RE: PATCH: matching in the new completion system
  1999-04-12  9:07 Sven Wischnowsky
  1999-04-13  9:56 ` Andrej Borsenkow
@ 1999-04-13 12:46 ` Andrej Borsenkow
  1999-04-13 12:35   ` Peter Stephenson
  1 sibling, 1 reply; 15+ messages in thread
From: Andrej Borsenkow @ 1999-04-13 12:46 UTC (permalink / raw)
  To: Sven Wischnowsky, zsh-workers

Is it intentional? 

(implying /usr/share/man/mrd)

bor@itsrm2:/tools/src/zsh-3.1.5-pws-14/Completion%> zsh -f
itsrm2% fpath=(*(/))
itsrm2% source Core/compinit 
bor@itsrm2:~%> l /u/s/m/m<TAB>
itsrm2% l /usr/s<TAB>
itsrm2% l /usr/s  
sadm/    sbin/    share/   spool@   src/     sysadm/  

Note, that if I also do:

itsrm2% compconf completer=_complete:_match
itsrm2% compconf match_original=yes
itsrm2% setopt no_listambiguous

itsrm2% l /u/s/m/m<TAB>
itsrm2% l /usr/s<TAB>  
sadm/   share/  
itsrm2% l /usr/sadm/<TAB>
sadm/   share/  
itsrm2% l /usr/sbin/   <= !!
sadm/   share/  

Funny, isn't it?

/andrej


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: PATCH: matching in the new completion system
  1999-04-13 12:46 ` Andrej Borsenkow
@ 1999-04-13 12:35   ` Peter Stephenson
  0 siblings, 0 replies; 15+ messages in thread
From: Peter Stephenson @ 1999-04-13 12:35 UTC (permalink / raw)
  To: zsh-workers

"Andrej Borsenkow" wrote:
> Is it intentional? 
> 
> (implying /usr/share/man/mrd)
> 
> bor@itsrm2:/tools/src/zsh-3.1.5-pws-14/Completion%> zsh -f
> itsrm2% fpath=(*(/))
> itsrm2% source Core/compinit 
> bor@itsrm2:~%> l /u/s/m/m<TAB>
> itsrm2% l /usr/s<TAB>
> itsrm2% l /usr/s  
> sadm/    sbin/    share/   spool@   src/     sysadm/  

It gets worse after that.  If I now go back and do /u/s/<TAB>, the whole
shell hangs completely and has to be killed from somewhere else.  (I just
started off with /u/s/m<TAB>, but it all looks similar.)

-- 
Peter Stephenson <pws@ibmth.df.unipi.it>       Tel: +39 050 844536
WWW:  http://www.ifh.de/~pws/
Dipartimento di Fisica, Via Buonarroti 2, 56127 Pisa, Italy


^ permalink raw reply	[flat|nested] 15+ messages in thread

* RE: PATCH: matching in the new completion system
@ 1999-04-13 10:39 Sven Wischnowsky
  0 siblings, 0 replies; 15+ messages in thread
From: Sven Wischnowsky @ 1999-04-13 10:39 UTC (permalink / raw)
  To: zsh-workers


Andrej Borsenkow wrote:

> bor@itsrm2:/tools/src/zsh-3.1.5-pws-14%> ./configure --pre=/to<TAB>
> bor@itsrm2:/tools/src/zsh-3.1.5-pws-14%> ./configure /tools/

Yup, forgot to propagate `I{PRE,SUF}FIX'.

Bye
 Sven

diff -u oc/Core/_path_files Completion/Core/_path_files
--- oc/Core/_path_files	Mon Apr 12 11:09:16 1999
+++ Completion/Core/_path_files	Tue Apr 13 12:34:15 1999
@@ -276,13 +276,13 @@
 	  compadd -Uf -p "$linepath$testpath" -s "/${tmp3#*/}" \
 	          -W "$prepath$realpath$testpath" "$ignore[@]" \
 		  "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \
-		  "$group[@]" "$expl[@]" \
+		  "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
 		  - "${(@)tmp1%%/*}"
 	else
 	  compadd -Uf -p "$linepath$testpath" \
 	          -W "$prepath$realpath$testpath" "$ignore[@]" \
 		   "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \
-		   "$group[@]" "$expl[@]" \
+		   "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
 		   - "$tmp1[@]"
 	fi
       else
@@ -291,7 +291,7 @@
 	    compadd -Uf -p "$linepath$testpath" -s "/${i#*/}" \
 		    -W "$prepath$realpath$testpath" "$ignore[@]" \
 		    "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \
-		    "$group[@]" "$expl[@]" \
+		    "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
 		    - "${i%%/*}"
 	  done
         else
@@ -299,7 +299,7 @@
 	    compadd -Uf -p "$linepath$testpath" \
 		    -W "$prepath$realpath$testpath" "$ignore[@]" \
 		    "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \
-		    "$group[@]" "$expl[@]" \
+		    "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
 		    - "$i"
 	  done
         fi
@@ -329,7 +329,7 @@
     compadd -Uf -p "$linepath$testpath" \
 	    -W "$prepath$realpath$testpath" "$ignore[@]" \
 	    "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \
-	    "$group[@]" "$expl[@]" \
+	    "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
 	    - "$tmp1[@]"
   fi
 done

--
Sven Wischnowsky                         wischnow@informatik.hu-berlin.de


^ permalink raw reply	[flat|nested] 15+ messages in thread

* RE: PATCH: matching in the new completion system
  1999-04-12  9:07 Sven Wischnowsky
@ 1999-04-13  9:56 ` Andrej Borsenkow
  1999-04-13 12:46 ` Andrej Borsenkow
  1 sibling, 0 replies; 15+ messages in thread
From: Andrej Borsenkow @ 1999-04-13  9:56 UTC (permalink / raw)
  To: Sven Wischnowsky, zsh-workers

     No doubt,
>   Andrej will sooner or later tell us about the problems he finds ;-)

Not a problem, but a bug :-)

bor@itsrm2:/tools/src/zsh-3.1.5-pws-14%> ./configure --pre=/to<TAB>
bor@itsrm2:/tools/src/zsh-3.1.5-pws-14%> ./configure /tools/


cheers

/andrej

This is with all post-pws14 patches including these of Bart.


^ permalink raw reply	[flat|nested] 15+ messages in thread

* PATCH: matching in the new completion system
@ 1999-04-12  9:07 Sven Wischnowsky
  1999-04-13  9:56 ` Andrej Borsenkow
  1999-04-13 12:46 ` Andrej Borsenkow
  0 siblings, 2 replies; 15+ messages in thread
From: Sven Wischnowsky @ 1999-04-12  9:07 UTC (permalink / raw)
  To: zsh-workers


As Andrej has pointed out, the need for the `_match_*' function in the 
new completion system is a bad thing. I agree with that (although my
answers to his mails probably didn't show that).

He suggested adding `(#...)' glob flags to support `compctl -M' style
modifications of a glob pattern, which I didn't really like because it 
looked like something too specialised to be worth supporting in the
core.

So I have been thinking about two other ways to get rid of the
`_match_*' functions and the patch below implements one of them. One
of the reasons to make it this way is that it is really simple to
implement ;-)

The patch adds two more options to `compadd': `-O' and `-A', both get
an array-name as their argument. If at least one of them is given, the 
words given as possible matches are not stored as completions by the
code, but instead are just stored in the array whose name is
given. The interesting bit, of course, is that `compadd' also does
matching (unless the `-U' option is given), which allows one to easily 
check for matching strings in completion functions by just doing
something like: `compadd -O foo - ...'.

The difference between `-A' and `-O' is that `-O' stores the original
strings unchanged and `-A' uses the strings built while the matching
is done. With `-M "L:|no="' and `nof' on the line, matching the string
`foo' will store `nofoo' with the `-A' option and `foo' with the `-O'
option.

Some more comments:

- The exmaple files have been changed to make use of this, of course.
  This means that the `_match_*' functions may now be removed.
- The `_path_files' function has changed a lot. It was the hardest
  function to change and I took the chance to rewrite most of it. It
  is much smaller now, should be more readable, and probably faster.
  Of course, this means that I may have failed to re-implement the
  behavior of the old version under every circumstance. No doubt,
  Andrej will sooner or later tell us about the problems he finds ;-)
  Andrej, if you want to make me happy, you'll first collect the
  problems before posting them -- you pointed out too many things for
  me to remember, but I hope most things are ok.
- The patch also modifies the the `README' file (remember to invoke
  `patch' with `-p0'). I don't think that I'll do this again, trying
  to move only to the `compsys.yo' file. Maybe Peter will make the
  `README' file disappear (or change it to contain only a pointer to
  `compsys.yo' or the manual in general).

Anyway, I'll hope you agree that this is a good thing to have.

Bye
 Sven

diff -u os/utils.c Src/utils.c
--- os/utils.c	Thu Apr  1 15:09:06 1999
+++ Src/utils.c	Wed Apr  7 23:30:29 1999
@@ -3177,10 +3177,7 @@
 	*v++ = *u;
     }
     *v = '\0';
-    if (strcmp(buf, s))
-	tt = dupstring(buf);
-    else
-	tt = s;
+    tt = dupstring(buf);
     v += tt - buf;
     if (e && (sf & 1))
 	*e += tt - buf;
diff -u os/Zle/comp1.c Src/Zle/comp1.c
--- os/Zle/comp1.c	Thu Apr  1 15:09:22 1999
+++ Src/Zle/comp1.c	Wed Apr  7 21:25:22 1999
@@ -52,7 +52,7 @@
 /* pointers to functions required by compctl and defined by zle */
 
 /**/
-int (*addmatchesptr) _((char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, int, int, Cmatcher, char *, char **));
+int (*addmatchesptr) _((char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, int, int, Cmatcher, char *, char *, char *, char **));
 
 /**/
 char *(*comp_strptr) _((int *, int *, int));
diff -u os/Zle/compctl.c Src/Zle/compctl.c
--- os/Zle/compctl.c	Wed Apr  7 21:12:34 1999
+++ Src/Zle/compctl.c	Wed Apr  7 21:24:48 1999
@@ -1694,7 +1694,7 @@
     char *p, **sp, *e;
     char *ipre = NULL, *isuf = NULL, *ppre = NULL, *psuf = NULL, *prpre = NULL;
     char *pre = NULL, *suf = NULL, *group = NULL, *m = NULL, *rs = NULL;
-    char *ign = NULL, *rf = NULL, *expl = NULL;
+    char *ign = NULL, *rf = NULL, *expl = NULL, *apar = NULL, *opar = NULL;
     int f = 0, a = CAF_MATCH, dm;
     Cmatcher match = NULL;
 
@@ -1791,6 +1791,14 @@
 		sp = &rf;
 		e = "function name expected after -%c";
 		break;
+	    case 'A':
+		sp = &apar;
+		e = "parameter name expected after -%c";
+		break;
+	    case 'O':
+		sp = &opar;
+		e = "parameter name expected after -%c";
+		break;
 	    case '-':
 		argv++;
 		goto ca_args;
@@ -1824,7 +1832,7 @@
 
     match = cpcmatcher(match);
     a = addmatchesptr(ipre, isuf, ppre, psuf, prpre, pre, suf, group,
-		      rs, rf, ign, f, a, match, expl, argv);
+		      rs, rf, ign, f, a, match, expl, apar, opar, argv);
     freecmatcher(match);
 
     return a;
diff -u os/Zle/zle_tricky.c Src/Zle/zle_tricky.c
--- os/Zle/zle_tricky.c	Wed Apr  7 21:02:56 1999
+++ Src/Zle/zle_tricky.c	Fri Apr  9 23:47:44 1999
@@ -3444,6 +3444,22 @@
     return cm;
 }
 
+/* This stores the strings from the list in an array. */
+
+static void
+set_param(char *name, LinkList l)
+{
+    char **a, **p;
+    LinkNode n;
+
+    a = (char **) zalloc((countlinknodes(l) + 1) * sizeof(char *));
+    for (p = a, n = firstnode(l); n; incnode(n))
+	*p++ = ztrdup((char *) getdata(n));
+    *p = NULL;
+
+    setaparam(name, a);
+}
+
 /* This is used by compadd to add a couple of matches. The arguments are
  * the strings given via options. The last argument is the array with
  * the matches. */
@@ -3453,22 +3469,29 @@
 addmatches(char *ipre, char *isuf,
 	   char *ppre, char *psuf, char *prpre, char *pre,
 	   char *suf, char *group, char *rems, char *remf, char *ign,
-	   int flags, int aflags, Cmatcher match, char *exp, char **argv)
+	   int flags, int aflags, Cmatcher match, char *exp, 
+	   char *apar, char *opar, char **argv)
 {
     char *s, *ms, *lipre = NULL, *lisuf = NULL, *lpre = NULL, *lsuf = NULL;
     char **aign = NULL;
     int lpl, lsl, pl, sl, bpl, bsl, llpl = 0, llsl = 0, nm = mnum;
-    int oisalt = 0, isalt, isexact;
+    int oisalt = 0, isalt, isexact, doadd;
     Cline lc = NULL;
     Cmatch cm;
     struct cmlist mst;
     Cmlist oms = mstack;
     Comp cp = NULL;
+    LinkList aparl = NULL, oparl = NULL;
 
     /* Switch back to the heap that was used when the completion widget
      * was invoked. */
     SWITCHHEAPS(compheap) {
 	HEAPALLOC {
+	    doadd = (!apar && !opar);
+	    if (apar)
+		aparl = newlinklist();
+	    if (opar)
+		oparl = newlinklist();
 	    if (exp) {
 		expl = (Cexpl) zhalloc(sizeof(struct cexpl));
 		expl->count = expl->fcount = 0;
@@ -3596,7 +3619,7 @@
 		    rems = dupstring(rems);
 
 		/* Probably quote the prefix and suffix for testing. */
-		if (!cp && !(aflags & CAF_QUOTE)) {
+		if (!cp && (aflags & CAF_MATCH) && !(aflags & CAF_QUOTE)) {
 		    lpre = quotename(lpre, NULL);
 		    lsuf = quotename(lsuf, NULL);
 		    llpl = strlen(lpre);
@@ -3619,6 +3642,9 @@
 			if ((filell = strlen(*pt)) < sl
 			    && !strcmp(*pt, s + sl - filell))
 			    isalt = 1;
+
+		    if (isalt && !doadd)
+			continue;
 		}
 		if (!(aflags & CAF_MATCH)) {
 		    ms = dupstring(s);
@@ -3629,15 +3655,27 @@
 					     &bpl, &bsl, &isexact)))
 		    continue;
 
-		cm = add_match_data(isalt, ms, lc, ipre, ipre, isuf, pre, 
-				    prpre, ppre, psuf, suf, bpl, bsl,
-				    flags, isexact);
-		cm->rems = rems;
-		cm->remf = remf;
+		if (doadd) {
+		    cm = add_match_data(isalt, ms, lc, ipre, ipre, isuf, pre, 
+					prpre, ppre, psuf, suf, bpl, bsl,
+					flags, isexact);
+		    cm->rems = rems;
+		    cm->remf = remf;
+		} else {
+		    if (apar)
+			addlinknode(aparl, ms);
+		    if (opar)
+			addlinknode(oparl, s);
+		    free_cline(lc);
+		}
 	    }
 	    compnmatches = mnum;
 	    if (exp)
 		addexpl();
+	    if (apar)
+		set_param(apar, aparl);
+	    if (opar)
+		set_param(opar, oparl);
 	} LASTALLOC;
     } SWITCHBACKHEAPS;
 
diff -u od/Zsh/compsys.yo Doc/Zsh/compsys.yo
--- od/Zsh/compsys.yo	Thu Apr  1 15:08:57 1999
+++ Doc/Zsh/compsys.yo	Sat Apr 10 15:41:03 1999
@@ -648,59 +648,6 @@
 accepts the option `tt(-t)'. If this is given, completion is only done
 on words starting with two hyphens.
 )
-item(tt(_match_test))(
-This function is called at the beginning of functions that do matching in
-shell code with one argument: the name of the calling function. It
-should test the value of `tt($compstate[matcher])' and return non-zero
-if the calling function should try to generate matches for the global
-match specification in use.
-
-If you have a global match specification with more than one set of patterns
-you may want to modify this function to return non-zero for all of your
-match specifications and modify the function tt(_match_pattern) to build the
-pattern to use in the calling function.
-)
-item(tt(_match_pattern))(
-This function is called from functions that do matching whenever they
-need to build a pattern that is used to match possible completions.
-It gets the name of the calling function and two names of parameters
-as arguments. The first one is used in the calling function to build
-the pattern used for matching possible completions. The content of this
-parameter on entry to this function is the string taken from the line.
-Here it should be changed to a pattern that matches words as the match
-specifications currently in use do.
-
-In the calling function this pattern may be changed again or used only 
-in parts. The second parameter whose name is given as the third argument
-allows to give pattern flags like `tt(LPAR()#l)tt(RPAR())' that are to
-be used whenever matching is done.
-
-As an example, if you have global match specifications like:
-
-indent(nofill(
-tt(compctl -M 'm:{a-z}={A-Z}' 'm:{a-z}={A-Z} r:|[.-]=* r:|=*')))
-
-This function should look like:
-
-indent(nofill(
-tt(eval "${3}='(#l)'")
-tt([[ compstate[matcher] -eq 2 ]] && eval "$2='${(P)2:gs/./*./:gs/-/*-/}'")))
-
-The first line makes sure that matching is done case-insensitively as
-specified by `tt(m:{a-z}={A-Z})'. The second line replaces dots and hyphens
-in the given string by patterns matching any characters before them,
-like the `tt(r:|[.-]=* r:|=*)'. To make this work, the function `_match_test'
-would have to be changed to `tt(LPAR()LPAR() compstate[matcher] <= 2 RPAR()RPAR())'.
-
-When correction is used (see above), you probably don't want to set
-matching flags here as that may make the results slightly
-unpredictable. For this, change the line above to:
-
-indent(nofill(
-tt([[ compstate[matcher] -lt 0 ]] && eval "${3}='(#l)'")))
-
-The default implementation of this function is empty.
-)
 enditem()
 
 Apart from the functions explained, the tt(Base) sub-directory
diff -u od/Zsh/compwid.yo Doc/Zsh/compwid.yo
--- od/Zsh/compwid.yo	Thu Apr  1 15:08:57 1999
+++ Doc/Zsh/compwid.yo	Sat Apr 10 15:40:28 1999
@@ -336,7 +336,8 @@
 xitem([ tt(-W) var(file-prefix) ])
 xitem([ tt(-J) var(name) ] [ tt(-V) var(name) ] [ tt(-X) var(explanation) ])
 xitem([ tt(-r) var(remove-chars) ] [ tt(-R) var(remove-func) ])
-item([ tt(-M) var(match-spec) ] [ tt(--) ] [ var(words) ... ])(
+xitem([ tt(-M) var(match-spec) ] [ tt(-O) var(array) ] [ tt(-A) var(array) ])
+item([ tt(--) ] [ var(words) ... ])(
 
 This builtin command can be used to add matches and directly control
 all the information the completion code stores with each possible
@@ -504,6 +505,23 @@
 Note that with tt(compadd) this option does not automatically turn on
 menu completion if tt(AUTO_LIST) is set as the same options for the
 tt(compctl) and tt(compgen) builtin command do.
+)
+item(tt(-O) var(array))(
+If this option is given, the var(words) are em(not) added to the set of
+possible completions. Instead, matching is done as usual and all
+var(words) given as arguments that are matched will be stored in the
+array parameter whose name is given as var(array).
+)
+item(tt(-A) var(array))(
+Like the tt(-O) option this keeps the var(words) from being stored as
+possible completions. The matching words are instead stored in the array
+parameter given as var(array). In difference to the tt(-O) option this
+does not store the unchanged var(words) given as arguments, but instead
+the strings the completion code generated while matching. For example,
+with a matching specification of `tt(-M "L:|no=")', the string `tt(nof)'
+on the line and the string `tt(foo)' as one of the var(words), this option
+will make the string `tt(nofoo)' be stored in the array, whereas the tt(-O)
+option stores the `tt(foo)' originally given.
 )
 item(tt(-), tt(--))(
 This flag ends the list of flags and options. All arguments after it
diff -u -r oc/Base/_long_options Completion/Base/_long_options
--- oc/Base/_long_options	Thu Apr  1 15:09:52 1999
+++ Completion/Base/_long_options	Thu Apr  8 19:20:53 1999
@@ -200,20 +200,6 @@
   osuf="$SUFFIX"
 
   pre="${str%%\=*}"
-  IPREFIX="${IPREFIX}${pre}="
-  PREFIX="${str#*\=}"
-  SUFFIX=""
-
-  # We will check if the arrays contain an option matching what's on
-  # the line. To do this good, we build a pattern.
-
-  [[ -n "$_comp_correct" && $#pre -le _comp_correct ]] && return 1
-
-  pat="${pre}*"
-  patflags=''
-  _match_pattern _long_options pat patflags
-
-  [[ -n "$_comp_correct" ]] && patflags="$patflags(#a$_comp_correct)"
 
   # Then we walk through the array names. For each array we test if it 
   # contains the option string. If so, we `invoke' the action stored
@@ -223,6 +209,9 @@
   for name in "$_lo_cache_names[@]"; do
     action="$_lo_cache_actions[anum]"
     if (( ${(@)${(@P)name}[(I)$pre]} )); then
+      IPREFIX="${oipre}${pre}="
+      PREFIX="${str#*\=}"
+      SUFFIX=""
       if [[ "$action[1]" = (\[|\() ]]; then
         compadd - ${=action[2,-2]}
       elif (( $#action )); then
@@ -240,7 +229,10 @@
     # element from `_lo_actions' in `parta'. If we find more than one
     # such option or if we already had one, we set `parto' to `-'.
 
-    tmp=("${(@M)${(@P)name}:#${~pat}}")
+    PREFIX="${str%%\=*}"
+    SUFFIX=""
+    compadd -O tmp -M 'r:|-=* r:|=*' - "${(@P)name}"
+
     if [[ $#tmp -eq 1 ]]; then
       if [[ -z "$parto" ]]; then
         parto="$tmp[1]"
@@ -258,8 +250,9 @@
   # try to complete the string after the `='.
 
   if [[ -n "$parto" && "$parto" != - ]]; then
-    IPREFIX="${parto}="
-
+    IPREFIX="${oipre}${parto}="
+    PREFIX="${str#*\=}"
+    SUFFIX=""
     if (( $#parta )); then
       if [[ "$parta[1]" = (\[|\() ]]; then
         compadd - ${=parta[2,-2]}
@@ -281,7 +274,7 @@
 
 # The string on the line did not contain a `=', or we couldn't
 # complete the option string since there were more than one matching
-# what's on the line. So we just ad the option string as possible
+# what's on the line. So we just add the option strings as possible
 # matches, giving the string from the `=' on as a suffix.
 
 if [[ "$str" = *\=* ]]; then
diff -u -r oc/Core/_multi_parts Completion/Core/_multi_parts
--- oc/Core/_multi_parts	Thu Apr  1 15:09:50 1999
+++ Completion/Core/_multi_parts	Fri Apr  9 20:29:17 1999
@@ -7,15 +7,8 @@
 # The parts of words from the array that are separated by the
 # separator character are then completed independently.
 
-local sep matches patstr orig matchflags pref i tmp1 tmp2 nm
-local group expl menu origflags mflags
-
-_match_test _multi_parts || return 1
-
-# Save the current number of matches to be able to return if we added
-# matches or not.
-
-nm=$compstate[nmatches]
+local sep matches pref npref i tmp1 group expl menu pre suf
+typeset -U tmp2
 
 # Get the options.
 
@@ -41,193 +34,159 @@
   matches=( "${(@P)2}" )
 fi
 
-# Now build the pattern from what we have on the line. We also save
-# the original string in `orig'.
+# In `pre' and `suf' we will hold the prefix and the suffix from the
+# line while we walk through them. The original string are used 
+# temporarily for matching.
+
+pre="$PREFIX"
+suf="$SUFFIX"
+orig="$PREFIX$SUFFIX"
 
-if [[ $#compstate[pattern_match] -ne 0 ]]; then
-  if [[ "${compstate[pattern_match]-*}" = \** ]]; then
-    str="${PREFIX}*${SUFFIX}*"
-  else
-    str="${PREFIX}${SUFFIX}"
-  fi
-else
-  patstr="${PREFIX:q}*${SUFFIX:q}*"
-fi
-orig="${PREFIX}${SUFFIX}"
+# Special handling for menucompletion?
 
 [[ $compstate[insert] = (*menu|[0-9]*) || -n "$_comp_correct" ||
    ( $#compstate[pattern_match] -ne 0 &&
      "$orig" != "${orig:q}" ) ]] && menu=yes
 
-matchflags=""
-_match_pattern _path_files patstr matchflags
-origflags="$matchflags"
-[[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)"
-
-patstr="${${patstr//$sep/*$sep}//\*##/*}"
-
-# First we will skip over those parts of the matches for which we have 
-# exact substrings on the line. In `pref' we will build the
-# unambiguous prefix string.
+# In `pref' we collect the unambiguous prefix path.
 
 pref=''
-while [[ "$orig" = *${sep}* ]] do
 
-  # First build the pattern to use, then collect all strings from
-  # `matches' that match the prefix we have and the exact substring in 
-  # the array `tmp1'.
+# If the string from the line matches at least one of the strings,
+# we use only the matching strings.
 
-  if [[ -n "$_comp_correct" && "${#orig%%${sep}*}" -le _comp_correct ]]; then
-    mflags="$origflags"
-  else
-    mflags="$matchflags"
-  fi
+compadd -O tmp1 -M "r:|${sep}=* r:|=*" - "$matches[@]"
 
-  pat="${${${patstr#*${sep}}%${sep}*}//\*/[^${sep}]#}"
-  tmp1=( "${(@M)matches:#${~mflags}${orig%%${sep}*}${sep}${~pat}}" )
+(( $#tmp1 )) && matches=( "$tmp1[@]" )
 
-  # If there are no words matching the exact substring, stop.
+while true; do
 
-  (( $#tmp1 )) || break
+  # Get the prefix and suffix for matching.
 
-  # Otherwise add the part to the prefix, remove it from the matches
-  # (and also remove all words not matching the string at all), and
-  # set `patstr' and `orig' to the next component.
-
-  tmp1="${orig%%${sep}*}${sep}"
-  pref="$pref$tmp1"
-  matches=("${(@)${(@)${(@M)matches:#${tmp1}*}#$tmp1}:#}")
-  orig="${orig#*${sep}}"
-  patstr="${patstr#*${sep}}"
-done
+  if [[ "$pre" = *${sep}* ]]; then
+    PREFIX="${pre%%${sep}*}"
+    SUFFIX=""
+  else
+    PREFIX="${pre}"
+    SUFFIX="${suf%%${sep}*}"
+  fi
 
-# Now we get all the words that still match in `tmp1'.
+  # Check if the component for some of the possible matches is equal
+  # to the string from the line. If there are such strings, we directly
+  # use the stuff from the line. This avoids having `foo' complete to
+  # both `foo' and `foobar'.
 
-if [[ "$patstr" = *${sep}* ]]; then
-  tmp1="${patstr%${sep}*}${sep}"
-  pat="${tmp1//\*/[^${sep}]#}${patstr##*${sep}}"
-else
-  pat="$patstr"
-fi
-if [[ -n "$_comp_correct" && "${#orig%%${sep}*}" -le _comp_correct ]]; then
-  mflags="$origflags"
-else
-  mflags="$matchflags"
-fi
-tmp1=( "${(@M)matches:#${~mflags}${~pat}}" )
+  tmp1=( "${(@M)matches:#${PREFIX}${SUFFIX}${sep}*}" )
 
-if (( $#tmp1 )); then
+  if (( $#tmp1 )); then
+    npref="${PREFIX}${SUFFIX}${sep}"
+  else
+    # No exact match, see how many strings match what's on the line.
 
-  # There are words that are matched, put them into `matches' and then
-  # move all unambiguous components from the beginning into `pref'.
+    tmp2=( "${(@)matches%%${sep}*}" )
+    compadd -O tmp1 - "$tmp2[@]"
 
-  matches=( "$tmp1[@]" )
-  while [[ "$matches[1]" = *${sep}* ]]; do
+    if [[ $#tmp1 -eq 1 ]]; then
 
-    # We just take the first component of the first match and see if
-    # there are other matches with a different prefix (these are
-    # collected in `tmp2'). If there are any, we give up.
+      # Only one match. If there are still separators from the line
+      # we just accept this component. Otherwise we insert what we 
+      # have collected, probably giving it a separator character
+      # as a suffix.
 
-    tmp1="${matches[1]%%${sep}*}${sep}"
-    tmp2=( "${(@)matches:#${tmp1}*}" )
-    (( $#tmp2 )) && break
+      if [[ "$pre$suf" = *${sep}* ]]; then
+        npref="${tmp1[1]}${sep}"
+      else
+        matches=( "${(@M)matches:#${tmp1[1]}*}" )
+	tmp2=( "${(@M)matches:#${tmp1[1]}${sep}*}" )
 
-    # All matches have the same prefix, put it into `pref' and remove
-    # it from the matches.
+	if (( $#tmp2 )); then
+	  compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
+	          -p "$pref" -qS "$sep" - "$tmp1[1]"
+        else
+	  compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
+	          -p "$pref" - "$tmp1[1]"
+        fi
+	return 1
+      fi
+    elif (( $#tmp1 )); then
 
-    pref="$pref$tmp1"
-    matches=( "${(@)${(@)matches#$tmp1}:#}" )
+      # More than one match. First we get all strings that match the
+      # rest from the line.
 
-    if [[ "$orig" = *${sep}* ]]; then
-      orig="${orig#*${sep}}"
+      PREFIX="$pre"
+      SUFFIX="$suf"
+      compadd -O matches -M "r:|${sep}=* r:|=*" - "$matches[@]"
+
+      if [[ -n "$menu" ]]; then
+        # With menucompletion we just add matches for the matching
+        # components with the prefix we collected and the rest from the
+        # line as a suffix.
+
+        tmp2="$pre$suf"
+        if [[ "$tmp2" = *${sep}* ]]; then
+          compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
+	          -p "$pref" -s "${sep}${tmp2#*${sep}}" - "$tmp1[@]"
+        else
+          compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
+	          -p "$pref" - "$tmp1[@]"
+        fi
+      else
+        # With normal completion we add all matches one-by-one with
+	# the unmatched part as a suffix. This will insert the longest
+	# unambiguous string for all matching strings.
+
+        for i in "${(@M)matches:#(${(j:|:)~tmp1})*}"; do
+	  if [[ "$i" = *${sep}* ]]; then
+            compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
+	            -S '' -p "$pref" -s "${i#*${sep}}" - "${i%%${sep}*}${sep}"
+          else
+            compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
+	            -S '' -p "$pref" - "$i"
+          fi
+        done
+      fi
+      return 0
     else
-      orig=''
-    fi
-  done
+      # We are here if no string matched what's on the line. In this
+      # case we insert the expanded prefix we collected if it differs
+      # from the original string from the line.
 
-  # Now we can tell the completion code about the things we
-  # found. Strings that have a separator will be added with a suffix.
+      [[ "$orig" = "$pref$pre$suf" ]] && return 1
 
-  if [[ -z "$orig" && "$PREFIX$SUFFIX" != "$pref$orig" ]]; then
-    compadd -QU  "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" -S '' - \
-            "${pref}${orig}"
-  elif [[ -n "$menu" ]]; then
-    if [[ "$orig" = *${sep}* ]]; then
-      orig="${sep}${orig#*${sep}}"
-    else
-      orig=''
-    fi
-    for i in "$matches[@]" ; do
-      if [[ "$i" = *${sep}* ]]; then
+      if [[ -n "$suf" ]]; then
         compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
-	        -p "$pref" -s "$orig" - "${i%%${sep}*}${sep}"
+	        -s "$suf" - "$pref$pre"
       else
         compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
-	        -p "$pref" -s "$orig" - "${i%%${sep}*}"
+	        -S '' - "$pref$pre$suf"
       fi
-    done
-  else
-    for i in "$matches[@]" ; do
-      if [[ "$i" = *${sep}* ]]; then
-        compadd -U -i "$IPREFIX" -I "$ISUFFIX" -p "$pref" -s "${i#*${sep}}" \
-	        "$group[@]" "$expl[@]" -M "r:|${sep:q}=*" - "${i%%${sep}*}${sep}"
-      else
-        compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
-                -p "$pref" - "$i"
-      fi
-    done
-  fi
-elif [[ "$patstr" = *${sep}* ]]; then
-
-  # We had no words matching the string from the line. But we want to
-  # be friendly and at least expand the prefix as far as we can. So we 
-  # will loop through the rest of the string from the line and test
-  # the components one by one.
-
-  while [[ "$patstr" = *${sep}* ]]; do
-
-    # First we get all words matching at least this component in
-    # `tmp1'. If there are none, we give up.
-
-    if [[ -n "$_comp_correct" && "${#orig%%${sep}*}" -le _comp_correct ]]; then
-      mflags="$origflags"
-    else
-      mflags="$matchflags"
-    fi
-    tmp1=( "${(@M)matches:#${~mflags}${~patstr%%${sep}*}${sep}*}" )
-    (( $#tmp1 )) || break
-
-    # Then we check if there are words that have a different prefix.
-
-    tmp2=( "${(@)tmp1:#${tmp1[1]%%${sep}*}${sep}*}" )
-    if (( $#tmp2 )); then
-
-      # There are words with another prefix, so we have found an
-      # ambiguous component. So we just give all possible prefixes to
-      # the completion code together with our prefix and the rest of
-      # the string from the line as the suffix.
-
-      compadd -U "$group[@]" "$expl[@]" -S '' -i "$IPREFIX" -I "$ISUFFIX" \
-              -p "$pref" -s "${sep}${orig#*${sep}}" - "${(@)matches%%${sep}*}"
       return 0
     fi
+  fi
 
-    # All words have the same prefix, so add it to `pref' again and
-    # try the next component.
-
-    pref="$pref${tmp1[1]%%${sep}*}${sep}"
-    matches=( "${(@)matches#${tmp1[1]%%${sep}*}${sep}}" )
-    orig="${orig#*${sep}}"
-    patstr="${patstr#*${sep}}"
-  done
-
-  # Finally, add the unambiguous prefix and the rest of the string
-  # from the line.
-
-  compadd -U "$group[@]" "$expl[@]" -S '' -i "$IPREFIX" -I "$ISUFFIX" \
-          -p "$pref" - "$orig"
-fi
+  # We just accepted and/or expanded a component from the line. We
+  # remove it from the matches (using only those that have a least
+  # the skipped string) and ad it the `pref'.
+
+  matches=( "${(@)${(@)${(@M)matches:#${npref}*}#*${sep}}:#}" )
+  pref="$pref$npref"
+
+  # Now we set `pre' and `suf' to their new values.
+
+  if [[ "$pre" = *${sep}* ]]; then
+    pre="${pre#*${sep}}"
+  elif [[ "$suf" = *${sep}* ]]; then
+    pre="${suf#*${sep}}"
+    suf=""
+  else
+    # The string from the line is fully handled. If we collected an
+    # unambiguous prefix and that differs from the original string,
+    # we insert it.
 
-# This sets the return value to indicate that we added matches (or not).
+    [[ -n "$pref" && "$orig" != "$pref" ]] &&
+        compadd -U "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" \
+	        -S '' - "$pref"
 
-[[ nm -ne compstate[nmatches] ]]
+    return
+  fi
+done
--- oc/Core/_path_files	Thu Apr  1 15:09:49 1999
+++ Completion/Core/_path_files	Sun Apr 11 23:37:25 1999
@@ -17,22 +17,13 @@
 #    If this is set to a non-empty string, the partially typed path
 #    from the line will be expanded as far as possible even if trailing
 #    pathname components can not be completed.
-#
-#
-# This function uses the helper functions `_match_test' and `_match_pattern'.
 
-# First see if we should generate matches for the global matcher in use.
+local linepath realpath donepath prepath testpath exppath
+local tmp1 tmp2 tmp3 tmp4 i orig pre suf tpre tsuf
+local pats ignore group expl addpfx addsfx remsfx
+local nm=$compstate[nmatches] menu
 
-_match_test _path_files || return 1
-
-# Yes, so...
-
-local nm str linepath realpath donepath patstr prepath testpath rest
-local tmp1 collect tmp2 suffixes i ignore matchflags opt group sopt pats gopt
-local addpfx addsfx expl orig ostr nm=$compstate[nmatches] menu remsfx patlast
-local origflags mflags tmp3 tmp4 exppaths
-
-typeset -U prepaths
+typeset -U prepaths exppaths
 
 setopt localoptions nullglob rcexpandparam extendedglob
 unsetopt markdirs globsubst shwordsplit nounset
@@ -108,61 +99,24 @@
   fi
 fi
 
-# str holds the whole string from the command line with a `*' between
-# the prefix and the suffix. Then we see if we will do menucompletion.
+# We get the prefix and the suffix from the line and save the whole
+# original string. Then we see if we will do menucompletion.
 
-if [[ $#compstate[pattern_match] -ne 0 ]]; then
-  if [[ "${compstate[pattern_match]-*}" = \** ]]; then
-    str="${PREFIX}*${SUFFIX}"
-  else
-    str="${PREFIX}${SUFFIX}"
-  fi
-else
-  str="${PREFIX:q}*${SUFFIX:q}"
-  [[ "$str" = \\\~* ]] && str="$str[2,-1]"
-fi
+pre="$PREFIX"
+suf="$SUFFIX"
 orig="${PREFIX}${SUFFIX}"
 
 [[ $compstate[insert] = (*menu|[0-9]*) || -n "$_comp_correct" ||
    ( $#compstate[pattern_match] -ne 0 &&
      "${orig#\~}" != "${${orig#\~}:q}" ) ]] && menu=yes
 
-
-# We will first try normal completion called with `compgen', but only if we
-# weren't given a `-F', `-r', or `-R' option.
-
-if [[ $#ignore -eq 0 && $#remsfx -eq 0 && -z "$_comp_correct" ]]; then
-  # First build an array containing the `-W' option, if there is any and we
-  # want to use it. We don't want to use it if the string from the command line
-  # is a absolute path or relative to the current directory.
-
-  if [[ -z "$tmp1[1]" || "$str[1]" = [~/] || "$str" = (.|..)/* ]]; then
-    tmp1=()
-  else
-    tmp1=(-W "( $prepaths )")
-  fi
-
-  # Now call compgen.
-
-  nm=$compstate[nmatches]
-  if [[ -z "$gopt" ]]; then
-    compgen "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" "$tmp1[@]" $sopt
-  else
-    compgen "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" "$tmp1[@]" $sopt -g "$pats"
-  fi
-
-  # If this generated any matches, we don't want to do in-path completion.
-
-  [[ compstate[nmatches] -eq nm ]] || return 0
-fi
-
-# No `-F' option, so we want to use `fignore'.
+# If given no `-F' option, we want to use `fignore'.
 
 (( $#ignore )) || ignore=(-F fignore)
 
 # Now let's have a closer look at the string to complete.
 
-if [[ "$str[1]" = \~ ]]; then
+if [[ "$pre[1]" = \~ ]]; then
   # It begins with `~', so remember anything before the first slash to be able
   # to report it to the completion code. Also get an expanded version of it
   # (in `realpath'), so that we can generate the matches. Then remove that
@@ -170,10 +124,10 @@
   # paths and make sure that the loop below is run only once with an empty
   # prefix path by setting `prepaths'.
   
-  linepath="${str%%/*}/"
+  linepath="${pre%%/*}/"
   eval realpath\=$linepath
   [[ "$realpath" = "$linepath" ]] && return 1
-  str="${str#*/}"
+  pre="${pre#*/}"
   orig="${orig#*/}"
   donepath=''
   prepaths=( '' )
@@ -184,12 +138,12 @@
   linepath=''
   realpath=''
 
-  if [[ "$str[1]" = / ]]; then
+  if [[ "$pre[1]" = / ]]; then
     # If it is a absolut path name, we remove the first slash and put it in
     # `donepath' meaning that we treat it as the path that was already handled.
     # Also, we don't use the paths from `-W'.
 
-    str="$str[2,-1]"
+    pre="$pre[2,-1]"
     orig="$orig[2,-1]"
     donepath='/'
     prepaths=( '' )
@@ -197,279 +151,199 @@
     # The common case, we just use the string as it is, unless it begins with
     # `./' or `../' in which case we don't use the paths from `-W'.
     
-    [[ "$str" = (.|..)/* ]] && prepaths=( '' )
+    [[ "$pre" = (.|..)/* ]] && prepaths=( '' )
     donepath=''
   fi
 fi
 
-# Now build the glob pattern by calling `_match_pattern'.
-patstr="$str"
-matchflags=""
-_match_pattern _path_files patstr matchflags
-origflags="$matchflags"
-[[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)"
-
-# We almost expect the pattern to have changed `..' into `*.*.', `/.' into
-# `/*.', and probably to contain two or more consecutive `*'s. Since these
-# have special meaning for globbing, we remove them. But before that, we
-# add the pattern for matching any characters before a slash.
-
-patstr="$patstr:gs-/-*/-:gs/*.*./../:gs/**/*/"
-
-# We take the last pathname component from the pattern and store it in
-# `patlast', replacing `*'s in it with patterns that match any character
-# but not slashes. Later we will generate matches using `patstr' with the
-# patterns we were given (like `*.c') appended to it, producing all matching
-# files. These filenames are then compared to `patlast' and all names not
-# matching that will be removed. All this is needed to be able to correctly
-# support `completeinword' as otherwise we would have something like `a*x'
-# from the line (the `*' was inserted above) and appending the `-g' pattern
-# `*.tex' would yield `a*x*.tex' which is not what we want.
-
-if [[ "$patstr" = */* ]]; then
-  if [[ -n "$_comp_correct" && "${#orig##*/}" -le _comp_correct ]]; then
-    patlast="*/${origflags}${${${patstr##*/}//\*/[^/]#}:gs.\[^/]#.\\\*.}"
-  else
-    patlast="*/${matchflags}${${${patstr##*/}//\*/[^/]#}:gs.\[^/]#.\\\*.}"
-  fi
-  patstr="${patstr%/*}/"
-else
-  if [[ -n "$_comp_correct" && "$#orig" -le _comp_correct ]]; then
-    patlast="${origflags}${${patstr//\*/[^/]#}:gs.\[^/]#.\\\*.}"
-  else
-    patlast="${matchflags}${${patstr//\*/[^/]#}:gs.\[^/]#.\\\*.}"
-  fi
-  patstr=""
-fi
+# Now we generate the matches. First we loop over all prefix paths given
+# with the `-W' option.
 
-# First we skip over all pathname components in `str' which really exist in
-# the file-system, so that `/usr/lib/l<TAB>' doesn't offer you `lib' and
-# `lib5'. Pathname components skipped this way are taken from `orig' and added
-# to `donepath'.
-
-while [[ "$orig" = */* ]] do
-  tmp1=( $realpath$donepath${orig%%/*}/${~matchflags}${~patstr#*/}${^~pats} )
-  tmp1=("${(@M)tmp1:#$~patlast}")
-  [[ $#tmp1 -gt 0 && -e "$realpath$donepath${orig%%/*}" ]] || break
-  donepath="$donepath${orig%%/*}/"
-  orig="${orig#*/}"
-  patstr="${patstr#*/}"
-done
+for prepath in "$prepaths[@]"; do
 
-# Finally, generate the matches. First we loop over all the paths from `-W'.
-# Note that in this loop `str' is used as a modifyable version of `patstr'
-# and `testpath' is a modifyable version of `donepath'.
+  # Get local copies of the prefix, suffix, and the prefix path to use
+  # in the following loop, which walks through the pathname components
+  # in the string from the line.
 
-for prepath in "$prepaths[@]"; do
-  str="$patstr"
+  tpre="$pre"
+  tsuf="$suf"
   testpath="$donepath"
-  ostr="$orig"
 
-  [[ -z "$prepath" || "$prepath[-1]" = / ]] || prepath="${prepath}/"
+  tmp1=( "$prepath$realpath$donepath" )
+
+  while true; do
 
-  # The second loop tests the components of the path in `str' to get the
-  # possible matches.
+    # Skip over `./' and `../'.
+
+    if [[ "$tpre" = (.|..)/* ]]; then
+      tmp1=( ${^tmp1}${tpre%%/*}/ )
+      tpre="${tpre#*/}"
+      continue
+    fi
+
+    # Get the prefix and suffix for matching.
+
+    if [[ "$tpre" = */* ]]; then
+      PREFIX="${tpre%%/*}"
+      SUFFIX=""
+    else
+      PREFIX="${tpre}"
+      SUFFIX="${tsuf%%/*}"
+    fi
 
-  while [[ "$str" = */* ]] do
-    # `rest' is the pathname after the first slash that is left. In `tmp1'
-    # we get the globbing matches for the pathname component currently
-    # handled.
+    # Get the matching files by globbing.
 
-    if [[ -n "$_comp_correct" && "${#ostr%%/*}" -le _comp_correct ]]; then
-      mflags="$origflags"
+    if [[ "$tpre$tsuf" = */* ]]; then
+      tmp1=( ${^tmp1}*(D/) )
     else
-      mflags="$matchflags"
+      tmp1=( ${^tmp1}${^~pats} )
     fi
-    rest="${str#*/}"
-    tmp1="${prepath}${realpath}${testpath}${~mflags}${str%%/*}(-/)"
-    tmp1=( $~tmp1 )
-
-    if [[ $#tmp1 -eq 0 ]]; then
-      # If this didn't produce any matches, we don't need to test this path
-      # any further, so continue with the next `-W' path, if any.
 
+    # See which of them match what's on the line.
+
+    compadd -O tmp2 "$ignore[@]" - "${(@)tmp1##*/}"
+
+    # If no file matches, save the expanded path and continue with
+    # the outer loop.
+
+    if [[ $#tmp2 -eq 0 && "$tmp1[1]" = */* ]]; then
+      exppaths=( "$exppaths[@]" ${^tmp1%/*}/${tpre}${tsuf} )
       continue 2
-    elif [[ $#tmp1 -gt 1 ]]; then
-      # If it produced more than one match, we want to remove those which
-      # don't have possible following pathname components matching the 
-      # rest of the string we are completing. (The case with only one
-      # match is handled below.)
-      # In `collect' we will collect those of the produced pathnames that
-      # have a matching possible path-suffix. In `suffixes' we build an
-      # array containing strings build from the rest of the string to 
-      # complete and the glob patterns we were given as arguments.
-
-      collect=()
-      suffixes=( $rest$^pats )
-      suffixes=( "${(@)suffixes:gs.**.*.}" )
+    fi
 
-      if [[ -n "$_comp_correct" && "${#ostr#*/}" -le _comp_correct ]]; then
-        mflags="$origflags"
-      else
-        mflags="$matchflags"
-      fi
+    # Remove all files that weren't matched.
 
-      # In the loop the prefixes from the `tmp1' array produced above and
-      # the suffixes we just built are used to produce possible matches
-      # via globbing.
-
-      for i in "$tmp1[@]" ; do
-        tmp2=( ${~i}/${~mflags}${~suffixes} )
-        tmp2=("${(@M)tmp2:#$~patlast}")
-        [[ $#tmp2 -ne 0 ]] && collect=( $collect $i )
-      done
-
-      # If this test showed that none of the matches from the glob in `tmp1'
-      # has a possible sub-path matching what's on the line, we add the
-      # matches found in `tmp1' and otherwise give up and continue with the
-      # next `-W' path.
-
-      if [[ $#collect -eq 0 ]]; then
-        # Before giving up, we first try to get the longest expandable path-
-	# prefix, though. The result is stored in `exppaths'
-
-        tmp2=()
-	tmp3="$rest"
-	[[ "$tmp3[-1]" = / ]] && tmp3="$tmp3[1,-2](-/M)"
-	tmp4="${ostr##*/}"
-	ostr="${ostr%/*}"
-	while [[ "$ostr" = */* ]]; do
-	  tmp2=( ${^tmp1}/${~mflags}${~tmp3} )
-	  if [[ $#tmp2 -eq 1 ]]; then
-	    exppaths=( "$exppaths[@]" "${tmp2[1]}${tmp4}" )
-	    exppaths=( "${(@)exppaths#${prepath}${realpath}}" )
-	    break;
-          fi
-	  tmp3="${tmp3%/*}"
-	  tmp4="${ostr##*/}/${tmp4}"
-	  ostr="${ostr%/*}"
-        done
-        continue 2
-      elif [[ $#collect -ne 1 ]]; then
-        # If we have more than one possible match, this means that the
-	# pathname component currently handled is ambiguous, so we give
-	# it to the completion code.
-	# First we build the full path prefix in `tmp1'.
-
-        tmp1="$prepath$realpath$testpath"
-
-	# Now produce all matching pathnames in `collect'.
-
-        collect=( ${~collect}/${~matchflags}${~suffixes} )
-	collect=("${(@M)collect:#$~patlast}")
-
-	# And then remove the common path prefix from all these matches.
-
-        collect=( ${collect#$tmp1} )
-
-	# Finally, we add all these matches with the common (unexpanded)
-	# pathprefix (the `-p' option), the path-prefix (the `-W' option)
-	# to allow the completion code to test file type, and the path-
-	# suffix (the `-s' option). We also tell the completion code that
-	# these are file names and that `fignore' should be used as usual
-	# (the `-f' and `-F' options).
-
-	if [[ -n "$menu" ]]; then
-          compadd -QU "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" \
-                  -i "$IPREFIX" -I "$ISUFFIX" -p "$linepath${testpath:q}" \
-		  -s "/${ostr#*/}" \
-		  -W "$tmp1" -f "$ignore[@]" - "${(@)${(@)collect%%/*}:q}"
-	else
-          for i in $collect; do
-            compadd -QU "$addpfx[@]" "$addsfx[@]" "$group[@]" "$expl[@]" \
-	            -i "$IPREFIX" -I "$ISUFFIX" \
-                    -p "$linepath${testpath:q}" -s "/${${i#*/}:q}" \
-		    -M 'r:|/=*' -W "$tmp1" -f "$ignore[@]" - "${${i%%/*}:q}"
-          done
-	fi
+    if [[ "$tmp1[1]" = */* ]]; then
+      tmp1=( "${(@M)tmp1:#*/(${(j:|:)~tmp2})}" )
+    else
+      tmp1=( "${(@M)tmp1:#(${(j:|:)~tmp2})}" )
+    fi
+
+    # Step over to the next component, if any.
+
+    if [[ "$tpre" = */* ]]; then
+      tpre="${tpre#*/}"
+    elif [[ "$tsuf" = */* ]]; then
+      tpre="${tsuf#*/}"
+      tsuf=""
+    else
+      break
+    fi
+
+    # There are more components, so add a slash to the files we are
+    # collecting.
+
+    tmp1=( ${^tmp1}/ )
+  done
+
+  # The next loop searches the first ambiguous component.
+
+  tmp3="$pre$suf"
+  tmp1=( "${(@)tmp1#${prepath}${realpath}${testpath}}" )
 
-	# We have just finished handling all the matches from above, so we
-	# can continue with the next `-W' path.
+  while true; do
 
-	continue 2
+    # 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 avoid having `foo' complete to `foo' and `foobar'.
+
+    if [[ "$tmp3" = */* ]]; then
+      tmp4=( "${(@M)tmp1:#${tmp3%%/*}/*}" )
+      if (( $#tmp4 )); then
+        tmp1=( "$tmp4[@]" )
       fi
+    fi
+
+    # Next we see if this component is ambiguous.
+
+    if [[ "$tmp3" = */* ]]; then
+      tmp4=( "${(@)tmp1:#${tmp1[1]%%/*}/*}" )
+    else
+      tmp4=( "${(@)tmp1:#${tmp1[1]}}" )
+    fi
+
+    if (( $#tmp4 )); then
 
-      # We reach this point if only one of the path prefixes in `tmp1'
-      # has a existing path-suffix matching the string from the line.
-      # In this case we accept this match and continue with the next
-      # path-name component.
-
-      tmp1=( "$collect[1]" )
-    elif [[ -n "$_comp_correct" && "$mflags" = "$matchflags" ]]; then
-
-      # If we got only one match with auto-correction and if we get none
-      # without correction, stop now.
-
-      tmp2="${prepath}${realpath}${testpath}${~origflags}${str%%/*}(-/)"
-      tmp2=( $~tmp2 )
-
-      if [[ $#tmp1 -ne $#tmp2 ]]; then
-        compadd -QU "$addpfx[@]" -S '' "$group[@]" "$expl[@]" \
-                -i "$IPREFIX" -I "$ISUFFIX" \
-                -p "$linepath${testpath:q}" -s "/${ostr#*/}" \
-		- "${${tmp1#${prepath}${realpath}${testpath}}:q}"
-        continue 2
+      # It is. For menucompletion we now add the possible completions
+      # for this component with the unambigous prefix we have built
+      # and the rest of the string from the line as the suffix.
+      # For normal completion we add the rests of the filenames
+      # collected as the suffixes to make the completion code expand
+      # it as far as possible.
+
+      if [[ -n $menu ]]; then
+        if [[ "$tmp3" = */* ]]; then
+	  compadd -Uf -p "$linepath$testpath" -s "/${tmp3#*/}" \
+	          -W "$prepath$realpath$testpath" "$ignore[@]" \
+		  "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \
+		  "$group[@]" "$expl[@]" \
+		  - "${(@)tmp1%%/*}"
+	else
+	  compadd -Uf -p "$linepath$testpath" \
+	          -W "$prepath$realpath$testpath" "$ignore[@]" \
+		   "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \
+		   "$group[@]" "$expl[@]" \
+		   - "$tmp1[@]"
+	fi
+      else
+        if [[ "$tmp3" = */* ]]; then
+          for i in "$tmp1[@]"; do
+	    compadd -Uf -p "$linepath$testpath" -s "/${i#*/}" \
+		    -W "$prepath$realpath$testpath" "$ignore[@]" \
+		    "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \
+		    "$group[@]" "$expl[@]" \
+		    - "${i%%/*}"
+	  done
+        else
+          for i in "$tmp1[@]"; do
+	    compadd -Uf -p "$linepath$testpath" \
+		    -W "$prepath$realpath$testpath" "$ignore[@]" \
+		    "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \
+		    "$group[@]" "$expl[@]" \
+		    - "$i"
+	  done
+        fi
       fi
+      tmp4=-
+      break
     fi
-    # This is also reached if the first globbing produced only one match
-    # in this case we just continue with the next pathname component, too.
 
-    tmp1="$tmp1[1]"
-    testpath="$testpath${tmp1##*/}/"
-    str="$rest"
-    ostr="${ostr#*/}"
-  done
+    # If we have checked all components, we stop now and add the 
+    # strings collected after the loop.
 
-  # We are here if all pathname components except the last one (which is still
-  # not tested) are unambiguous. So we add matches with the full path prefix, 
-  # no path suffix, the `-W' we are currently handling, all the matches we
-  # can produce in this directory, if any.
+    if [[ "$tmp3" != */* ]]; then
+      tmp4=""
+      break
+    fi
 
-  if [[ -n "$_comp_correct" && "${#ostr#*/}" -le _comp_correct ]]; then
-    mflags="$origflags"
-  else
-    mflags="$matchflags"
-  fi
-  tmp1="$prepath$realpath$testpath"
-  suffixes=( $str$^pats )
-  suffixes=( "${(@)suffixes:gs.**.*.}" )
-  tmp2=( ${~tmp1}${~matchflags}${~suffixes} )
-  if [[ "$tmp1" = */* && "$patlast" != \*/* ]]; then
-    tmp2=("${(@M)tmp2:#*${~patlast}}")
-  else
-    tmp2=("${(@M)tmp2:#$~patlast}")
-  fi
-  if [[ $#tmp2 -eq 0 ]]; then
-    # No match, insert the expanded path and add the original tail.
+    # Otherwise we add the unambiguous component to `testpath' and
+    # take it from the filenames.
 
-    [[ "$testpath[-1]" = / ]] && testpath="$testpath[1,-2]"
-    [[ -z "$testpath" && "$linepath[-1]" = / ]] && linepath="$linepath[1,-2]"
-    [[ -n "$ostr" && -n "$linepath$testpath" ]] && ostr="/$ostr"
+    testpath="${testpath}${tmp1[1]%%/*}/"
+    tmp1=( "${(@)tmp1#*/}" )
 
-    # But only if something changed.
-    [[ "${PREFIX}${SUFFIX}" = $linepath$testpath$ostr(|/) ]] && return 1
+    tmp3="${tmp3#*/}"
+  done
 
-    compadd -QU -S '' "$group[@]" "$expl[@]" \
-            -i "$IPREFIX" -I "$ISUFFIX" -f - "$linepath${testpath:q}$ostr"
-  else
-    compadd -QU "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" "$group[@]" "$expl[@]" \
-            -i "$IPREFIX" -I "$ISUFFIX" \
-            -p "$linepath${testpath:q}" -f "$ignore[@]" \
-	    -W "$prepath$realpath$testpath" - "${(@)${(@)tmp2#$tmp1}:q}"
+  if [[ -z "$tmp4" ]]; then
+    compadd -Uf -p "$linepath$testpath" \
+	    -W "$prepath$realpath$testpath" "$ignore[@]" \
+	    "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \
+	    "$group[@]" "$expl[@]" \
+	    - "$tmp1[@]"
   fi
 done
 
-# If no matches were found but we have expanded paths which are different
-# from the original string, use them.
+# If we are configured to expand paths as far as possible and we collected
+# expanded paths that are different from the string on the line, we add
+# them as possible matches.
 
 exppaths=( "${(@)exppaths:#$orig}" )
 
 if [[ -n "$compconfig[path_expand]" &&
-      nm -eq compstate[nmatches] && $#exppaths -ne 0 ]]; then
-  compadd -UQ -S '' "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" - \
-          "${linepath}${(@)^exppaths}"
+      $#exppaths -ne 0 && nm -eq compstate[nmatches] ]]; then
+  compadd -U -S '' "$group[@]" "$expl[@]" -i "$IPREFIX" -I "$ISUFFIX" - \
+          "${(@)exppaths}"
 fi
 
-# This sets the return value to indicate that we added matches (or not).
-
-[[ nm -ne compstate[nmatches] ]]
+[[ nm -eq compstate[nmatches] ]]
diff -u -r oc/Core/_sep_parts Completion/Core/_sep_parts
--- oc/Core/_sep_parts	Thu Apr  1 15:09:50 1999
+++ Completion/Core/_sep_parts	Thu Apr  8 19:34:46 1999
@@ -9,24 +9,17 @@
 #
 #  _sep_parts '(foo bar)' @ hosts
 #
-# This will make this function complete the strings in the array
-# `friends'. If the string on the line contains a `@', the substring
-# after it will be completed from the array `hosts'. Of course more
-# arrays may be given, each preceded by another separator string.
+# This will make this function complete the strings `foo' and `bar'
+# If the string on the line contains a `@', the substring after it
+# will be completed from the array `hosts'. Of course more arrays
+# may be given, each preceded by another separator string.
 #
 # This function understands the `-J group', `-V group', and
 # `-X explanation' options.
-#
-# This function does part of the matching itself and calls the functions
-# `_match_test' and `_match_pattern' for this.
 
 local str arr sep test testarr tmparr prefix suffixes matchers autosuffix
 local matchflags opt group expl nm=$compstate[nmatches]
 
-# Test if we should use this function for the global matcher in use.
-
-_match_test _sep_parts || return 1
-
 # Get the options.
 
 group=()
@@ -42,7 +35,7 @@
 # Get the string from the line.
 
 str="$PREFIX$SUFFIX"
-[[ $#compstate[pattern_match] -ne 0 ]] || str="$str:q"
+SUFFIX=""
 prefix=""
 
 # Walk through the arguments to find the longest unambiguous prefix.
@@ -56,61 +49,49 @@
     tmparr=( ${=arr[2,-2]} )
     arr=tmparr
   fi
+
   # Is the separator on the line?
-  [[ "$str" != *${sep}* ]] && break
 
-  # Build a pattern matching the possible matches and get all these
-  # matches in an array.
+  [[ "$str" != *${sep}* ]] && break
 
-  test="${str%%${sep}*}"
-  [[ -n "$_comp_correct" && $#test -le _comp_correct ]] && return 1
+  # Get the matching array elements.
 
-  matchflags=""
-  _match_pattern _sep_parts test matchflags
-  [[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)"
-
-  test="${matchflags}${test}"
-  testarr=( "${(@M)${(@P)arr}:#${~test}*}" )
-  testarr=( "${(@)testarr:#}" )
+  PREFIX="${str%%${sep}*}"
+  compadd -O testarr - "${(@P)arr}"
 
   # If there are no matches we give up. If there is more than one
   # match, this is the part we will complete.
+
   (( $#testarr )) || return 1
   [[ $#testarr -gt 1 ]] && break
 
   # Only one match, add it to the prefix and skip over it in `str',
   # continuing with the next array and separator.
+
   prefix="${prefix}${testarr[1]}${sep}"
   str="${str#*${sep}}"
   shift 2
 done
 
 # Get the array to work upon.
+
 arr="$1"
 if [[ "$arr[1]" == '(' ]]; then
   tmparr=( ${=arr[2,-2]} )
   arr=tmparr
 fi
+
 if [[ $# -le 1 || "$str" != *${2}* ]]; then
   # No more separators, build the matches.
 
-  test="$str"
-  [[ -n "$_comp_correct" && $#test -le _comp_correct ]] && return 1
-
-  matchflags=""
-  _match_pattern _sep_parts test matchflags
-  [[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)"
-
-  [[ "${compstate[pattern_match]-*}" != \** ]] && test="$test:gs/*//"
-
-  test="${matchflags}${test}"
-  testarr=( "${(@M)${(@P)arr}:#${~test}*}" )
-  testarr=( "${(@)testarr:#}" )
+  PREFIX="$str"
+  compadd -O testarr - "${(@P)arr}"
 fi
 
 [[ $#testarr -eq 0 || ${#testarr[1]} -eq 0 ]] && return 1
 
 # Now we build the suffixes to give to the completion code.
+
 shift
 matchers=()
 suffixes=("")
@@ -118,26 +99,18 @@
 
 while [[ $# -gt 0 && "$str" == *${1}* ]]; do
   # Remove anything up to the the suffix.
+
   str="${str#*${1}}"
 
   # Again, we get the string from the line up to the next separator
   # and build a pattern from it.
+
   if [[ $# -gt 2 ]]; then
-    test="${str%%${3}*}"
+    PREFIX="${str%%${3}*}"
   else
-    test="$str"
+    PREFIX="$str"
   fi
 
-  [[ -n "$_comp_correct" && $#test -le _comp_correct ]] && return 1
-
-  matchflags=""
-  _match_pattern _sep_parts test matchflags
-  [[ -n "$_comp_correct" ]] && matchflags="$matchflags(#a$_comp_correct)"
-
-  [[ "${compstate[pattern_match]-*}" != \** ]] && test="$test:gs/*//"
-
-  test="${matchflags}${test}"
-
   # We incrementally add suffixes by appending to them the seperators
   # and the strings from the next array that match the pattern we built.
 
@@ -146,26 +119,31 @@
     tmparr=( ${=arr[2,-2]} )
     arr=tmparr
   fi
-  tmparr=( "${(@M)${(@P)arr}:#${~test}*}" )
-  tmparr=( "${(@)tmparr:#}" )
+
+  compadd -O tmparr - "${(@P)arr}"
+
   suffixes=("${(@)^suffixes[@]}${1}${(@)^tmparr}")
 
   # We want the completion code to generate the most specific suffix
   # for us, so we collect matching specifications that allow partial
   # word matching before the separators on the fly.
+
   matchers=("$matchers[@]" "r:|${1:q}=*")
   shift 2
 done
 
 # If we were given at least one more separator we make the completion
 # code offer it by appending it as a autoremovable suffix.
+
 (( $# )) && autosuffix=(-qS "$1")
 
 # If we have collected matching specifications, we build an array
 # from it that can be used as arguments to `compadd'.
+
 [[ $#matchers -gt 0 ]] && matchers=(-M "$matchers")
 
 # Add the matches for each of the suffixes.
+
 for i in "$suffixes[@]"; do
   compadd -U "$group[@]" "$expl[@]" "$matchers[@]" "$autosuffix[@]" \
           -i "$IPREFIX" -I "$ISUFFIX" -p "$prefix" -s "$i" - "$testarr[@]"
diff -u -r oc/Core/compinit Completion/Core/compinit
--- oc/Core/compinit	Thu Apr  1 15:09:49 1999
+++ Completion/Core/compinit	Thu Apr  8 19:42:58 1999
@@ -39,11 +39,6 @@
 # were able to add matches and non-zero otherwise.
 #
 # See the file `compdump' for how to speed up initialisation.
-#
-# If you are using global matching specifications with `compctl -M ...'
-# have a look at the files `_match_test' and `_match_pattern'. To make
-# all the example functions use matching as specified with `-M' these
-# need some editing.
 
 # If we got the `-d'-flag, we will automatically dump the new state (at
 # the end).
diff -u -r oc/README Completion/README
--- oc/README	Thu Apr  1 15:09:46 1999
+++ Completion/README	Sat Apr 10 15:30:32 1999
@@ -110,13 +110,6 @@
     dangerous because the command from the line will be called with the
     --help option and hence could cause damage if used with a command
     that does not support it.
-  _match_pattern
-  _match_test
-    These are used by Base/_path_files (and hence also Base/_files)
-    and Base/_sep_parts for file completion with control over
-    matching (whether to complete case-insensitively, or to allow
-    insertion before `.', etc.)  See _match_test for instructions.
-    Note _path_files expects these files to be present.
   _precommand
     Allows completion when the first word on the line has to be ignored,
     for example `noglob ...' should ignore the noglob and just complete

--
Sven Wischnowsky                         wischnow@informatik.hu-berlin.de


^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~1999-04-28  7:44 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1999-04-26 13:39 PATCH: matching in the new completion system Sven Wischnowsky
1999-04-26 13:25 ` Peter Stephenson
1999-04-28  4:37 ` Bart Schaefer
  -- strict thread matches above, loose matches on Subject: below --
1999-04-28  7:44 Sven Wischnowsky
1999-04-14  8:31 Sven Wischnowsky
1999-04-14  6:19 Sven Wischnowsky
1999-04-14  7:50 ` Peter Stephenson
1999-04-13 13:18 Sven Wischnowsky
1999-04-13 14:39 ` Peter Stephenson
1999-04-14  6:15   ` Andrej Borsenkow
1999-04-13 10:39 Sven Wischnowsky
1999-04-12  9:07 Sven Wischnowsky
1999-04-13  9:56 ` Andrej Borsenkow
1999-04-13 12:46 ` Andrej Borsenkow
1999-04-13 12:35   ` Peter Stephenson

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).