Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Problem with completion matching control



I wrote:

> I'm tempted to remove the test that avoids calling the match-
> generation again, at least if the command line was changed. But then
> I'll have to make sure the interaction between listambiguous,
> automenu, autolist, bashautolist, and recexact still gives reasonable
> results, so this may take a while.

The patch below is a bit of an overhaul for the usage of completion
options in do_ambiguous(). A not-so-funny side effect is that the
match-generation code now gets called even if there is already a
list. This is needed to be able to detect when to use recexact
correctly, however.
User visible changes are that strings resulting from a `-M'-spec
behave the same as those from normal matching - this is in fact a bug
fix.
Another effect is that the automatically-use-automenu-if-recexact-is-set-
and-what-we-inserted-is-an-exact-match now magically appears after the 
list is shown, i.e. with possible matches `foo' and `foobar' and
listambiguous, automenu, and recexact set it completes `f' to `foo' of 
the first TAB, shows the list on the second TAB, and starts
menucompletion with the third TAB. This is the way automenu normally
behaves, so I hope you find it better than the `start menu-completion
and show the list now, ignoring listambiguous'-behavior we had before.
  

Bye
 Sven

diff -u os/Zle/zle_tricky.c Src/Zle/zle_tricky.c
--- os/Zle/zle_tricky.c	Mon Feb 15 12:51:57 1999
+++ Src/Zle/zle_tricky.c	Tue Feb 16 14:57:58 1999
@@ -287,6 +287,12 @@
 
 static int lastambig;
 
+/* Non-zero if the string on the line came from a previous completion. *
+ * This is used to detect if the string should be taken as an exact    *
+ * match (see do_ambiguous()).                                         */
+
+static int fromcomp;
+
 /**/
 void
 completecall(void)
@@ -2586,10 +2592,10 @@
 		    s = quotename(s, &e, te, &pl);
 		    sl = strlen(s);
 		}
-		if (!ms && ai->firstm) {
+		if (!ms) {
 		    if (sl < ai->minlen)
 			ai->minlen = sl;
-		    if ((i = sfxlen(ai->firstm->str, s)) < ai->suflen)
+		    if (ai->firstm && (i = sfxlen(ai->firstm->str, s)) < ai->suflen)
 			ai->suflen = i;
 		}
 		t = s;
@@ -2854,10 +2860,11 @@
     }
     if (!test)
 	return;
-    if (!ms && !ispattern && ai->firstm) {
+    if (!ms) {
 	if (sl < ai->minlen)
 	    ai->minlen = sl;
-	if ((test = sfxlen(ai->firstm->str, s)) < ai->suflen)
+	if (!ispattern && ai->firstm &&
+	    (test = sfxlen(ai->firstm->str, s)) < ai->suflen)
 	    ai->suflen = test;
     }
 
@@ -3464,14 +3471,13 @@
 
 static unsigned long ccont;
 
-/* Create the completion list.  This is called whenever some bit of  *
- * completion code needs the list.  If the list is already available *
- * (validlist!=0), this function doesn't do anything.  Along with    *
- * the list is maintained the prefixes/suffixes etc.  When any of    *
- * this becomes invalid -- e.g. if some text is changed on the       *
- * command line -- invalidatelist() should be called, to set         *
- * validlist to zero and free up the memory used.  This function     *
- * returns non-zero on error.                                        */
+/* Create the completion list.  This is called whenever some bit of   *
+ * completion code needs the list.                                    *
+ * Along with the list is maintained the prefixes/suffixes etc.  When *
+ * any of this becomes invalid -- e.g. if some text is changed on the *
+ * command line -- invalidatelist() should be called, to set          *
+ * validlist to zero and free up the memory used.  This function      *
+ * returns non-zero on error.                                         */
 
 /**/
 static int
@@ -3482,8 +3488,6 @@
 
     /* If we already have a list from a previous execution of this *
      * function, skip the list building code.                      */
-    if (validlist)
-	return !nmatches;
 
     if ((m = cmatcher)) {
 	Cmlist mm, *mp = &mm;
@@ -3515,7 +3519,8 @@
 
 	freecl = NULL;
 
-	lastambig = 0;
+	if (!validlist)
+	    lastambig = 0;
 	amatches = 0;
 	mnum = 0;
 	begcmgroup("default", 0);
@@ -5001,7 +5006,7 @@
 	listmatches();
     if(validlist)
 	freematches();
-    lastambig = menucmp = validlist = showinglist = 0;
+    lastambig = menucmp = validlist = showinglist = fromcomp = 0;
     menucur = NULL;
     compwidget = NULL;
 }
@@ -5437,14 +5442,13 @@
 do_ambiguous(void)
 {
     int p = (usemenu || ispattern), atend = (cs == we);
-    int am = 0;
 
     menucmp = 0;
 
     /* If we have to insert the first match, call do_single().  This is *
      * how REC_EXACT takes effect.  We effectively turn the ambiguous   *
      * completion into an unambiguous one.                              */
-    if (ainfo && ainfo->exact == 1 && isset(RECEXACT) &&
+    if (ainfo && ainfo->exact == 1 && isset(RECEXACT) && !fromcomp &&
 	(usemenu == 0 || unset(AUTOMENU))) {
 	do_single(ainfo->exactm);
 	invalidatelist();
@@ -5464,7 +5468,7 @@
 	 * normal menu completion options.                                 */
 	do_ambig_menu();
     } else {
-	int ics = cs, ocs, pl = 0, l, lp, ls;
+	int ics = cs, ocs, pl = 0, l, lp, ls, la = 0;
 	char *ps;
 	Cline lc;
 
@@ -5473,9 +5477,8 @@
 
 	fixsuffix();
 
-	/* Delete the old stuff from the command line. */
+	/* Prepare to delete the old stuff from the command line. */
 	cs = wb;
-	foredel(we - wb);
 
 	/* Sort-of general case: we have an ambiguous completion, and aren't *
 	 * starting menu completion or doing anything really weird.  We need *
@@ -5499,7 +5502,13 @@
 	    ls = ainfo->csl;
 	}
 	if (lc) {
-	    int sl = 0;
+	    VARARR(char, oline, ll);
+	    int sl = 0, oll = ll;
+
+	    memcpy(oline, line, ll);
+
+	    /* First remove the old string from the line. */
+	    foredel(we - wb);
 
 	    if (lp) {
 		if (ls) {
@@ -5514,7 +5523,21 @@
 		    merge_cline(lc, ps, lp, NULL, 0, 0);
 	    }
 	    inst_cline(lc, pl, sl);
+
+	    /* la is non-zero if listambiguous may be used. Copying and
+	     * comparing the line looks like BFI but it is the easiest
+	     * solution. Really. */
+	    la = (ll != oll || strncmp(oline, (char *) line, ll));
+
+	    /* If REC_EXACT and AUTO_MENU are set and what we inserted is an *
+	     * exact match, we want menu completion the next time round      *
+	     * so we set fromcomp,to ensure that the word on the line is not *
+	     * taken as an exact match.                                      */
+	    fromcomp = isset(AUTOMENU);
 	} else {
+	    /* First remove the old string from the line. */
+	    foredel(we - wb);
+
 	    inststrlen(ps, 1, -1);
 	    ocs = cs;
 	    if (brbeg && *brbeg) {
@@ -5535,24 +5558,21 @@
 		inststrlen(brend, 1, -1);
 	    }
 	    cs = ocs;
-	}
-	/* If REC_EXACT and AUTO_MENU are set and what we inserted is an   *
-	 * exact match, we want to start menu completion now. Otherwise    *
-	 * on the next call to completion the inserted string would be     *
-	 * taken as a match and no menu completion would be started.       */
-
-	if (isset(RECEXACT) && !lc && ps && ainfo->minlen == strlen(ps))
-	    am = 1;
+	    la = (ics != cs || (ainfo->suflen && !atend ));
 
+	    fromcomp = isset(AUTOMENU);
+	}
 	/*
 	 * If the LIST_AMBIGUOUS option (meaning roughly `show a list only *
 	 * if the completion is completely ambiguous') is set, and some    *
 	 * prefix was inserted, return now, bypassing the list-displaying  *
 	 * code.  On the way, invalidate the list and note that we don't   *
 	 * want to enter an AUTO_MENU imediately.                          */
-	if(isset(LISTAMBIGUOUS) && !am &&
-	   (ics != cs || (ainfo->suflen && !atend))) {
+	if(isset(LISTAMBIGUOUS) && la) {
+	    int fc = fromcomp;
+
 	    invalidatelist();
+	    fromcomp = fc;
 	    lastambig = 0;
 	    return;
 	}

--
Sven Wischnowsky                         wischnow@xxxxxxxxxxxxxxxxxxxxxxx



Messages sorted by: Reverse Date, Date, Thread, Author