about summary refs log tree commit diff
path: root/Src
diff options
context:
space:
mode:
authorTanaka Akira <akr@users.sourceforge.net>1999-10-13 13:43:02 +0000
committerTanaka Akira <akr@users.sourceforge.net>1999-10-13 13:43:02 +0000
commitace2616432ae930d29966bbb29a827a57e198dc3 (patch)
treecd0b7ebc0af5c79ad2891605d402f1d5b8651b1c /Src
parent18e3d1903d7978be38af678cf4414dd1a655a9e8 (diff)
downloadzsh-ace2616432ae930d29966bbb29a827a57e198dc3.tar.gz
zsh-ace2616432ae930d29966bbb29a827a57e198dc3.tar.xz
zsh-ace2616432ae930d29966bbb29a827a57e198dc3.zip
zsh-workers/8227
Diffstat (limited to 'Src')
-rw-r--r--Src/Zle/comp.h11
-rw-r--r--Src/Zle/comp1.c14
-rw-r--r--Src/Zle/compctl.c42
-rw-r--r--Src/Zle/complist.c51
-rw-r--r--Src/Zle/zle_main.c6
-rw-r--r--Src/Zle/zle_params.c9
-rw-r--r--Src/Zle/zle_tricky.c311
7 files changed, 312 insertions, 132 deletions
diff --git a/Src/Zle/comp.h b/Src/Zle/comp.h
index 201469872..091b04476 100644
--- a/Src/Zle/comp.h
+++ b/Src/Zle/comp.h
@@ -350,6 +350,7 @@ struct cldata {
     int nlist;			/* number of matches to list */
     int nlines;			/* number of lines needed */
     int hidden;			/* != 0 if there are hidden matches */
+    int onlyexpl;		/* != 0 if only explanations to print */
 };
 
 typedef void (*CLPrintFunc)(Cmgroup, Cmatch *, int, int, int, int,
@@ -440,8 +441,10 @@ struct chdata {
 #define CP_OLDINS      (1 << CPN_OLDINS)
 #define CPN_VARED      24
 #define CP_VARED       (1 << CPN_VARED)
-#define CPN_NNMATCHES  25
-#define CP_NNMATCHES   (1 << CPN_NNMATCHES)
+#define CPN_ANMATCHES  25
+#define CP_ANMATCHES   (1 << CPN_ANMATCHES)
+#define CPN_LISTLINES  26
+#define CP_LISTLINES   (1 << CPN_LISTLINES)
 
-#define CP_KEYPARAMS   26
-#define CP_ALLKEYS     ((unsigned int) 0xffffff)
+#define CP_KEYPARAMS   27
+#define CP_ALLKEYS     ((unsigned int) 0x7ffffff)
diff --git a/Src/Zle/comp1.c b/Src/Zle/comp1.c
index c1e2bfb57..f2b51c877 100644
--- a/Src/Zle/comp1.c
+++ b/Src/Zle/comp1.c
@@ -67,6 +67,15 @@ int (*makecomplistcallptr) _((Compctl));
 int (*makecomplistctlptr) _((int));
 
 /**/
+zlong (*num_matchesptr) _((int));
+
+/**/
+zlong (*list_linesptr) _((void));
+
+/**/
+void (*comp_listptr) _((char *));
+
+/**/
 char *(*unambig_dataptr) _((int *));
 
 /**/
@@ -104,11 +113,10 @@ int incompfunc;
 
 /**/
 zlong compcurrent,
-      compnmatches,
-      compnnmatches,
       compmatcher,
       compmatchertot,
-      complistmax;
+      complistmax,
+      complistlines;
 
 /**/
 char **compwords,
diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c
index ce80bbee5..1b72fa923 100644
--- a/Src/Zle/compctl.c
+++ b/Src/Zle/compctl.c
@@ -2249,7 +2249,7 @@ static struct compparam comprparams[] = {
 };
 
 static struct compparam compkparams[] = {
-    { "nmatches", PM_INTEGER, VAL(compnmatches), NULL, NULL },
+    { "nmatches", PM_INTEGER | PM_READONLY, NULL, NULL, VAL(get_nmatches) },
     { "matcher", PM_INTEGER, VAL(compmatcher), NULL, NULL },
     { "matcher_string", PM_SCALAR, VAL(compmatcherstr), NULL, NULL },
     { "total_matchers", PM_INTEGER, VAL(compmatchertot), NULL, NULL },
@@ -2259,7 +2259,7 @@ static struct compparam compkparams[] = {
     { "quote", PM_SCALAR | PM_READONLY, VAL(compquote), NULL, NULL },
     { "quoting", PM_SCALAR | PM_READONLY, VAL(compquoting), NULL, NULL },
     { "restore", PM_SCALAR, VAL(comprestore), NULL, NULL },
-    { "list", PM_SCALAR, VAL(complist), NULL, NULL },
+    { "list", PM_SCALAR, NULL, VAL(set_complist), VAL(get_complist) },
     { "force_list", PM_SCALAR, VAL(compforcelist), NULL, NULL },
     { "insert", PM_SCALAR, VAL(compinsert), NULL, NULL },
     { "exact", PM_SCALAR, VAL(compexact), NULL, NULL },
@@ -2275,7 +2275,8 @@ static struct compparam compkparams[] = {
     { "old_list", PM_SCALAR, VAL(compoldlist), NULL, NULL },
     { "old_insert", PM_SCALAR, VAL(compoldins), NULL, NULL },
     { "vared", PM_SCALAR, VAL(compvared), NULL, NULL },
-    { "normal_nmatches", PM_INTEGER, VAL(compnnmatches), NULL, NULL },
+    { "alternate_nmatches", PM_INTEGER | PM_READONLY, NULL, NULL, VAL(get_anmatches) },
+    { "list_lines", PM_INTEGER | PM_READONLY, NULL, NULL, VAL(get_listlines) },
     { NULL, 0, NULL, NULL, NULL }
 };
 
@@ -2383,6 +2384,41 @@ set_compstate(Param pm, HashTable ht)
 }
 
 /**/
+static zlong
+get_nmatches(Param pm)
+{
+    return num_matchesptr(1);
+}
+
+/**/
+static zlong
+get_anmatches(Param pm)
+{
+    return num_matchesptr(0);
+}
+
+/**/
+static zlong
+get_listlines(Param pm)
+{
+    return list_linesptr();
+}
+
+/**/
+static void
+set_complist(Param pm, char *v)
+{
+    comp_listptr(v);
+}
+
+/**/
+static char *
+get_complist(Param pm)
+{
+    return complist;
+}
+
+/**/
 static char *
 get_unambig(Param pm)
 {
diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c
index 112dea530..b9b0ca79d 100644
--- a/Src/Zle/complist.c
+++ b/Src/Zle/complist.c
@@ -525,9 +525,9 @@ struct menustack {
     char *line;
     char *brbeg;
     char *brend;
-    int cs, acc;
+    int cs, acc, nmatches;
     struct menuinfo info;
-    Cmgroup amatches, pmatches, lmatches;
+    Cmgroup amatches, pmatches, lastmatches, lastlmatches;
 };
 
 static int
@@ -538,7 +538,7 @@ domenuselect(Hookdef dummy, Chdata dat)
     Cmgroup *pg;
     Thingy cmd;
     Menustack u = NULL;
-    int i = 0, acc = 0, wishcol = 0, setwish = 0;
+    int i = 0, acc = 0, wishcol = 0, setwish = 0, oe = onlyexpl;
     char *s;
 
     HEAPALLOC {
@@ -555,6 +555,7 @@ domenuselect(Hookdef dummy, Chdata dat)
 	noselect = 0;
 	mselect = (*(minfo.cur))->gnum;
 	for (;;) {
+	    onlyexpl = 0;
 	    showinglist = -2;
 	    zrefresh();
 	    inselect = 1;
@@ -601,18 +602,23 @@ domenuselect(Hookdef dummy, Chdata dat)
 		memcpy(&(s->info), &minfo, sizeof(struct menuinfo));
 		s->amatches = amatches;
 		s->pmatches = pmatches;
-		s->lmatches = lmatches;
+		s->lastmatches = lastmatches;
+		s->lastlmatches = lastlmatches;
 		s->acc = menuacc;
 		s->brbeg = dupstring(brbeg);
 		s->brend = dupstring(brend);
+		s->nmatches = nmatches;
 		menucmp = menuacc = 0;
 		fixsuffix();
 		validlist = 0;
-		pmatches = NULL;
+		amatches = pmatches = lastmatches = NULL;
 		invalidatelist();
-		menucomplete(zlenoargs);
+		PERMALLOC {
+		    menucomplete(zlenoargs);
+		} LASTALLOC;
 		if (dat->num < 2 || !minfo.cur || !*(minfo.cur)) {
 		    noselect = clearlist = listshown = 1;
+		    onlyexpl = 0;
 		    zrefresh();
 		    break;
 		}
@@ -629,10 +635,12 @@ domenuselect(Hookdef dummy, Chdata dat)
 		s->line = dupstring((char *) line);
 		s->cs = cs;
 		memcpy(&(s->info), &minfo, sizeof(struct menuinfo));
-		s->amatches = s->pmatches = s->lmatches = NULL;
+		s->amatches = s->pmatches =
+		    s->lastmatches = s->lastlmatches = NULL;
 		s->acc = menuacc;
 		s->brbeg = dupstring(brbeg);
 		s->brend = dupstring(brend);
+		s->nmatches = nmatches;
 		acceptlast();
 		do_menucmp(0);
 		mselect = (*(minfo.cur))->gnum;
@@ -652,12 +660,15 @@ domenuselect(Hookdef dummy, Chdata dat)
 		menuacc = u->acc;
 		memcpy(&minfo, &(u->info), sizeof(struct menuinfo));
 		p = &(minfo.cur);
-		if (u->pmatches && pmatches != u->pmatches) {
-		    freematches();
+		if (u->lastmatches && lastmatches != u->lastmatches) {
+		    if (lastmatches)
+			freematches(lastmatches);
 		    amatches = u->amatches;
 		    pmatches = u->pmatches;
-		    lmatches = u->lmatches;
-		    hasperm = 1;
+		    lastmatches = u->lastmatches;
+		    lastlmatches = u->lastlmatches;
+		    nmatches = u->nmatches;
+		    hasoldlist = 1;
 		}
 		zsfree(brbeg);
 		zsfree(brend);
@@ -666,6 +677,7 @@ domenuselect(Hookdef dummy, Chdata dat)
 		u = u->prev;
 		clearlist = 1;
 		setwish = 1;
+		listdat.valid = 0;
 	    } else if (cmd == Th(z_redisplay)) {
 		redisplay(zlenoargs);
 		continue;
@@ -819,19 +831,11 @@ domenuselect(Hookdef dummy, Chdata dat)
 	    do_single(**p);
 	    mselect = (**p)->gnum;
 	}
-	if (u) {
-	    int hp = hasperm;
-	    Cmgroup m = pmatches;
+	if (u)
+	    for (; u; u = u->prev)
+		if (u->lastmatches != lastmatches)
+		    freematches(u->lastmatches);
 
-	    for (; u; u = u->prev) {
-		if (u->pmatches != m) {
-		    pmatches = u->pmatches;
-		    freematches();
-		}
-	    }
-	    pmatches = m;
-	    hasperm = hp;
-	}
 	selectlocalmap(NULL);
 	mselect = -1;
 	inselect = 0;
@@ -842,6 +846,7 @@ domenuselect(Hookdef dummy, Chdata dat)
 	}
 	if (!noselect) {
 	    showinglist = -2;
+	    onlyexpl = oe;
 	    zrefresh();
 	}
 	fdat = NULL;
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index beef708fb..d7ffbe259 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -979,6 +979,9 @@ setup_zle(Module m)
     getcpatptr = getcpat;
     makecomplistcallptr = makecomplistcall;
     makecomplistctlptr = makecomplistctl;
+    num_matchesptr = num_matches;
+    list_linesptr = list_lines;
+    comp_listptr = comp_list;
     unambig_dataptr = unambig_data;
     set_comp_sepptr = set_comp_sep;
 
@@ -1059,6 +1062,9 @@ finish_zle(Module m)
     getcpatptr = NULL;
     makecomplistcallptr = NULL;
     makecomplistctlptr = NULL;
+    num_matchesptr = NULL;
+    list_linesptr = NULL;
+    comp_listptr = NULL;
     unambig_dataptr = NULL;
     set_comp_sepptr = NULL;
 
diff --git a/Src/Zle/zle_params.c b/Src/Zle/zle_params.c
index 5ed846cd6..aa62786f5 100644
--- a/Src/Zle/zle_params.c
+++ b/Src/Zle/zle_params.c
@@ -73,6 +73,8 @@ static struct zleparam {
         unset_numeric, NULL },
     { "HISTNO", PM_INTEGER | PM_READONLY, NULL, FN(get_histno),
         zleunsetfn, NULL },
+    { "BUFFERLINES", PM_INTEGER | PM_READONLY, NULL, FN(get_bufferlines),
+        zleunsetfn, NULL },
     { NULL, 0, NULL, NULL, NULL, NULL }
 };
 
@@ -285,3 +287,10 @@ get_histno(Param pm)
 {
     return histline;
 }
+
+/**/
+static zlong
+get_bufferlines(Param pm)
+{
+    return nlnct;
+}
diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index 6e42a7d65..ebae044b9 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -136,16 +136,24 @@ static int brpl, brsl, brpcs, brscs, qbrpl, qbrsl, hasunqu;
 
 static LinkList matches, fmatches;
 
-/* This holds the list of matches-groups. lmatches is a pointer to the  *
- * last element in this list. */
+/* This holds the list of matches-groups. lastmatches holds the last list of 
+ * permanently allocated matches, pmatches is the same for the list
+ * currently built, amatches is the heap allocated stuff during completion
+ * (after all matches have been generated it is an alias for pmatches), and
+ * lmatches/lastlmatches is a pointer to the last element in the lists. */
 
 /**/
-Cmgroup pmatches, amatches, lmatches;
+Cmgroup lastmatches, pmatches, amatches, lmatches, lastlmatches;
 
-/* Non-zero if we have permanently allocated matches. */
+/* Non-zero if we have permanently allocated matches (old and new). */
 
 /**/
-int hasperm;
+int hasoldlist, hasperm;
+
+/* Non-zero if we have newly added matches. */
+
+/**/
+int newmatches;
 
 /* Number of permanently allocated matches and groups. */
 
@@ -153,13 +161,19 @@ static int permmnum, permgnum;
 
 /* The total number of matches and the number of matches to be listed. */
 
-static int nmatches, smatches;
+/**/
+int nmatches, smatches;
 
 /* !=0 if we have a valid completion list. */
 
 /**/
 int validlist;
 
+/* != 0 if only explanation strings should be printed */
+
+/**/
+int onlyexpl;
+
 /* Information about the matches for listing. */
 
 /**/
@@ -234,7 +248,7 @@ static Cmgroup mgroup;
 
 /* Match counters: all matches, normal matches (not alternate set). */
 
-static int mnum, nmnum;
+static int mnum;
 
 /* The match counter when unambig_data() was called. */
 
@@ -3899,8 +3913,6 @@ add_match_data(int alt, char *str, Cline line,
     ai->line = join_clines(ai->line, line);
 
     mnum++;
-    if (!alt)
-	nmnum++;
     ai->count++;
     
     /* Allocate and fill the match structure. */
@@ -3929,6 +3941,8 @@ add_match_data(int alt, char *str, Cline line,
     cm->rems = cm->remf = cm->disp = NULL;
     addlinknode((alt ? fmatches : matches), cm);
 
+    newmatches = 1;
+
     /* One more match for this explanation. */
     if (expl) {
 	if (alt)
@@ -4283,8 +4297,6 @@ addmatches(Cadata dat, char **argv)
 		    free_cline(lc);
 		}
 	    }
-	    compnmatches = mnum;
-	    compnnmatches = nmnum;
 	    if (dat->apar)
 		set_list_array(dat->apar, aparl);
 	    if (dat->opar)
@@ -4843,13 +4855,18 @@ docompletion(char *s, int lst, int incmd)
 		minfo.cur = NULL;
 		minfo.asked = 0;
 		do_single(m->matches[0]);
-		if (compforcelist && *compforcelist && uselist)
-		    showinglist = -2;
-		else
+		if (compforcelist && *compforcelist) {
+		    if (uselist)
+			showinglist = -2;
+		    else
+			clearlist = 1;
+		} else
 		    invalidatelist();
 	    }
 	} else {
 	    invalidatelist();
+	    if (compforcelist && *compforcelist)
+		clearlist = 1;
 	    cs = 0;
 	    foredel(ll);
 	    inststr(origline);
@@ -4858,6 +4875,9 @@ docompletion(char *s, int lst, int incmd)
 	/* Print the explanation strings if needed. */
 	if (!showinglist && validlist && usemenu != 2 && nmatches != 1 &&
 	    useline != 2 && (!oldlist || !listshown)) {
+	    onlyexpl = 1;
+	    showinglist = -2;
+#if 0
 	    Cmgroup g = amatches;
 	    Cexpl *e;
 	    int up = 0, tr = 1, nn = 0;
@@ -4894,6 +4914,7 @@ docompletion(char *s, int lst, int incmd)
 		    putc('\n', shout);
 		fflush(shout);
 	    }
+#endif
 	}
       compend:
 	for (n = firstnode(matchers); n; incnode(n))
@@ -5067,8 +5088,6 @@ callcompfunc(char *s, char *fn)
 	zsfree(compqisuffix);
 	compqisuffix = ztrdup(qisuf ? qisuf : "");
 	compcurrent = (usea ? (clwpos + 1 - aadd) : 0);
-	compnmatches = mnum;
-	compnnmatches = nmnum;
 
 	zsfree(complist);
 	switch (uselist) {
@@ -5103,7 +5122,7 @@ callcompfunc(char *s, char *fn)
 	    comptoend = ztrdup("match");
 	zsfree(compoldlist);
 	zsfree(compoldins);
-	if (hasperm && permmnum) {
+	if (hasoldlist && permmnum) {
 	    if (listshown)
 		compoldlist = "shown";
 	    else
@@ -5150,14 +5169,17 @@ callcompfunc(char *s, char *fn)
 
 	if (!complist)
 	    uselist = 0;
-	else if (!strcmp(complist, "list"))
+	else if (!strncmp(complist, "list", 4))
 	    uselist = 1;
-	else if (!strcmp(complist, "auto") || !strcmp(complist, "autolist"))
+	else if (!strncmp(complist, "auto", 4))
 	    uselist = 2;
-	else if (!strcmp(complist, "ambig") || !strcmp(complist, "ambiguous"))
+	else if (!strncmp(complist, "ambig", 5))
 	    uselist = 3;
 	else
 	    uselist = 0;
+
+	onlyexpl = (complist && strstr(complist, "expl"));
+
 	if (!compinsert)
 	    useline = 0;
 	else if (!strcmp(compinsert, "unambig") ||
@@ -5193,8 +5215,8 @@ callcompfunc(char *s, char *fn)
 	else
 	    movetoend = 2;
 
-	oldlist = (hasperm && compoldlist && !strcmp(compoldlist, "keep"));
-	oldins = (hasperm && minfo.cur &&
+	oldlist = (hasoldlist && compoldlist && !strcmp(compoldlist, "keep"));
+	oldins = (hasoldlist && minfo.cur &&
 		  compoldins && !strcmp(compoldins, "keep"));
 
 	zfree(comprpms, CP_REALPARAMS * sizeof(Param));
@@ -5287,13 +5309,13 @@ makecomplist(char *s, int incmd, int lst)
 	if (!validlist)
 	    lastambig = 0;
 	amatches = NULL;
-	mnum = nmnum = 0;
+	mnum = 0;
 	unambig_mnum = -1;
 	isuf = NULL;
 	insmnum = insgnum = 1;
 	insgroup = oldlist = oldins = 0;
 	begcmgroup("default", 0);
-	menucmp = menuacc = 0;
+	menucmp = menuacc = newmatches = onlyexpl = 0;
 
 	ccused = newlinklist();
 	ccstack = newlinklist();
@@ -5318,16 +5340,32 @@ makecomplist(char *s, int incmd, int lst)
 	if (oldlist) {
 	    nmatches = onm;
 	    validlist = 1;
-	    amatches = pmatches;
-
+	    amatches = lastmatches;
+	    lmatches = lastlmatches;
+	    if (pmatches) {
+		freematches(pmatches);
+		pmatches = NULL;
+		hasperm = 0;
+	    }
 	    redup(osi, 0);
 
 	    return 0;
 	}
 	PERMALLOC {
-	    permmatches();
+	    if (lastmatches) {
+		freematches(lastmatches);
+		lastmatches = NULL;
+	    }
+	    permmatches(1);
+	    amatches = pmatches;
 	} LASTALLOC;
 
+	lastmatches = pmatches;
+	lastlmatches = lmatches;
+	pmatches = NULL;
+	hasperm = 0;
+	hasoldlist = 1;
+
 	if (nmatches && !errflag) {
 	    validlist = 1;
 
@@ -5709,8 +5747,6 @@ makecomplistcall(Compctl cc)
 	    instring = ois;
 	    inbackt = oib;
 	    autoq = oaq;
-	    compnmatches = mnum;
-	    compnnmatches = nmnum;
 	} LASTALLOC;
     } SWITCHBACKHEAPS;
 
@@ -5785,8 +5821,6 @@ makecomplistctl(int flags)
 	    inbackt = oib;
 	    autoq = oaq;
 	    offs = ooffs;
-	    compnmatches = mnum;
-	    compnnmatches = nmnum;
 	    zsfree(cmdstr);
 	    freearray(clwords);
 	    cmdstr = os;
@@ -7145,8 +7179,11 @@ invalidatelist(void)
 {
     if (showinglist == -2)
 	listmatches();
-    if (validlist)
-	freematches();
+    if (validlist) {
+	freematches(lastmatches);
+	lastmatches = NULL;
+	hasoldlist = 0;
+    }
     lastambig = menucmp = menuacc = validlist = showinglist = fromcomp = 0;
     listdat.valid = 0;
     if (listshown < 0)
@@ -7463,6 +7500,7 @@ addexpl(void)
 	}
     }
     addlinknode(expls, expl);
+    newmatches = 1;
 }
 
 /* This duplicates one match. */
@@ -7500,32 +7538,42 @@ dupmatch(Cmatch m)
 /* This duplicates all groups of matches. */
 
 /**/
-static void
-permmatches(void)
+static int
+permmatches(int last)
 {
     Cmgroup g = amatches, n;
     Cmatch *p, *q;
     Cexpl *ep, *eq, e, o;
     Compctl *cp, *cq;
-    int nn, nl, ll, fi = 0, gn = 1, mn = 1, rn;
+    LinkList mlist;
+    static int fi = 0;
+    int nn, nl, ll, gn = 1, mn = 1, rn;
+
+    if (pmatches && !newmatches)
+	return fi;
+
+    newmatches = fi = 0;
 
-    if (hasperm)
-	freematches();
+    if (pmatches)
+	freematches(pmatches);
 
-    amatches = lmatches = NULL;
+    pmatches = lmatches = NULL;
     nmatches = smatches = 0;
 
     if (!ainfo->count) {
-	ainfo = fainfo;
+	if (last)
+	    ainfo = fainfo;
 	fi = 1;
     }
     while (g) {
 	HEAPALLOC {
 	    if (empty(g->lmatches))
 		/* We have no matches, try ignoring fignore. */
-		g->lmatches = g->lfmatches;
+		mlist = g->lfmatches;
+	    else
+		mlist = g->lmatches;
 
-	    g->matches = makearray(g->lmatches, 1, g->flags, &nn, &nl, &ll);
+	    g->matches = makearray(mlist, 1, g->flags, &nn, &nl, &ll);
 	    g->mcount = nn;
 	    if ((g->lcount = nn - nl) < 0)
 		g->lcount = 0;
@@ -7548,10 +7596,10 @@ permmatches(void)
 
 	if (!lmatches)
 	    lmatches = n;
-	if (amatches)
-	    amatches->prev = n;
-	n->next = amatches;
-	amatches = n;
+	if (pmatches)
+	    pmatches->prev = n;
+	n->next = pmatches;
+	pmatches = n;
 	n->prev = 0;
 	n->num = gn++;
 
@@ -7594,18 +7642,71 @@ permmatches(void)
 
 	g = g->next;
     }
-    for (g = amatches; g; g = g->next) {
+    for (g = pmatches; g; g = g->next) {
 	for (rn = 1, q = g->matches; *q; q++) {
 	    (*q)->rnum = rn++;
 	    (*q)->gnum = mn++;
 	}
     }
-    pmatches = amatches;
     hasperm = 1;
     permmnum = mn - 1;
     permgnum = gn - 1;
+
+    return fi;
+}
+
+/* Return the real number of matches. */
+
+/**/
+zlong
+num_matches(int normal)
+{
+    int alt;
+
+    PERMALLOC {
+	alt = permmatches(0);
+    } LASTALLOC;
+
+    if (normal)
+	return (alt ? 0 : nmatches);
+    else
+	return (alt ? nmatches : 0);
+}
+
+/* Return the number of screen lines needed for the list. */
+
+/**/
+zlong
+list_lines(void)
+{
+    Cmgroup oam;
+
+    PERMALLOC {
+	permmatches(0);
+    } LASTALLOC;
+
+    oam = amatches;
+    amatches = pmatches;
+    listdat.valid = 0;
+    calclist();
+    listdat.valid = 0;
+    amatches = oam;
+
+    return listdat.nlines;
 }
 
+/**/
+void
+comp_list(char *v)
+{
+    zsfree(complist);
+    complist = ztrdup(v);
+
+    onlyexpl = (v && strstr(v, "expl"));
+}
+
+/**/
+
 /* This frees one match. */
 
 /**/
@@ -7634,9 +7735,9 @@ freematch(Cmatch m)
 
 /**/
 void
-freematches(void)
+freematches(Cmgroup g)
 {
-    Cmgroup g = pmatches, n;
+    Cmgroup n;
     Cmatch *m;
     Cexpl *e;
     Compctl *c;
@@ -7670,8 +7771,6 @@ freematches(void)
 
 	g = n;
     }
-    hasperm = 0;
-    listdat.valid = 0;
 }
 
 /* Insert the given string into the command line.  If move is non-zero, *
@@ -8576,27 +8675,33 @@ printfmt(char *fmt, int n, int dopr, int doesc)
 		    break;
 		case 'B':
 		    b = 1;
-		    tcout(TCBOLDFACEBEG);
+		    if (dopr)
+			tcout(TCBOLDFACEBEG);
 		    break;
 		case 'b':
 		    b = 0; m = 1;
-		    tcout(TCALLATTRSOFF);
+		    if (dopr)
+			tcout(TCALLATTRSOFF);
 		    break;
 		case 'S':
 		    s = 1;
-		    tcout(TCSTANDOUTBEG);
+		    if (dopr)
+			tcout(TCSTANDOUTBEG);
 		    break;
 		case 's':
 		    s = 0; m = 1;
-		    tcout(TCSTANDOUTEND);
+		    if (dopr)
+			tcout(TCSTANDOUTEND);
 		    break;
 		case 'U':
 		    u = 1;
-		    tcout(TCUNDERLINEBEG);
+		    if (dopr)
+			tcout(TCUNDERLINEBEG);
 		    break;
 		case 'u':
 		    u = 0; m = 1;
-		    tcout(TCUNDERLINEEND);
+		    if (dopr)
+			tcout(TCUNDERLINEEND);
 		    break;
 		case '{':
 		    for (p++; *p && (*p != '%' || p[1] != '}'); p++, cc++)
@@ -8608,7 +8713,7 @@ printfmt(char *fmt, int n, int dopr, int doesc)
 			p--;
 		    break;
 		}
-		if (m) {
+		if (dopr && m) {
 		    if (b)
 			tcout(TCBOLDFACEBEG);
 		    if (s)
@@ -8697,7 +8802,8 @@ calclist(void)
     int max = 0, i;
     VARARR(int, mlens, nmatches + 1);
 
-    if (listdat.valid && menuacc == listdat.menuacc &&
+    if (listdat.valid && onlyexpl == listdat.onlyexpl &&
+	menuacc == listdat.menuacc &&
 	lines == listdat.lines && columns == listdat.columns)
 	return;
 
@@ -8705,7 +8811,7 @@ calclist(void)
 	char **pp = g->ylist;
 	int nl = 0, l, glong = 1, gshort = columns, ndisp = 0, totl = 0;
 
-	if (pp) {
+	if (!onlyexpl && pp) {
 	    /* We have an ylist, lets see, if it contains newlines. */
 	    hidden = 1;
 	    while (!nl && *pp)
@@ -8742,7 +8848,7 @@ calclist(void)
 		    pp++;
 		}
 	    }
-	} else {
+	} else if (!onlyexpl) {
 	    for (p = g->matches; (m = *p); p++) {
 		if (menuacc && !hasbrpsfx(m, minfo.prebr, minfo.postbr)) {
 		    m->flags |= CMF_HIDE;
@@ -8798,50 +8904,52 @@ calclist(void)
 		max = i;
 	}
     }
-    for (g = amatches; g; g = g->next) {
-	char **pp;
-	int glines = 0;
+    if (!onlyexpl) {
+	for (g = amatches; g; g = g->next) {
+	    char **pp;
+	    int glines = 0;
 
-	zfree(g->widths, 0);
-	g->widths = NULL;
+	    zfree(g->widths, 0);
+	    g->widths = NULL;
 
-	if ((pp = g->ylist)) {
-	    if (!(g->flags & CGF_LINES)) {
+	    if ((pp = g->ylist)) {
+		if (!(g->flags & CGF_LINES)) {
+		    if (g->cols) {
+			glines += (arrlen(pp) + g->cols - 1) / g->cols;
+			if (g->cols > 1)
+			    g->width += (max - (g->width * g->cols - add)) / g->cols;
+		    } else {
+			g->cols = 1;
+			g->width = 1;
+			
+			while (*pp)
+			    glines += 1 + (strlen(*pp++) / columns);
+		    }
+		}
+	    } else {
 		if (g->cols) {
-		    glines += (arrlen(pp) + g->cols - 1) / g->cols;
+		    glines += (g->dcount + g->cols - 1) / g->cols;
 		    if (g->cols > 1)
 			g->width += (max - (g->width * g->cols - add)) / g->cols;
-		} else {
+		} else if (!(g->flags & CGF_LINES)) {
 		    g->cols = 1;
-		    g->width = 1;
-
-		    while (*pp)
-			glines += 1 + (strlen(*pp++) / columns);
+		    g->width = 0;
+		    
+		    for (p = g->matches; (m = *p); p++)
+			if (!(m->flags & CMF_HIDE)) {
+			    if (m->disp) {
+				if (!(m->flags & CMF_DISPLINE))
+				    glines += 1 + (mlens[m->gnum] / columns);
+			    } else if (!(m->flags & CMF_NOLIST))
+				glines += 1 + ((1 + mlens[m->gnum]) / columns);
+			}
 		}
 	    }
-	} else {
-	    if (g->cols) {
-		glines += (g->dcount + g->cols - 1) / g->cols;
-		if (g->cols > 1)
-		    g->width += (max - (g->width * g->cols - add)) / g->cols;
-	    } else if (!(g->flags & CGF_LINES)) {
-		g->cols = 1;
-		g->width = 0;
-
-		for (p = g->matches; (m = *p); p++)
-		    if (!(m->flags & CMF_HIDE)) {
-			if (m->disp) {
-			    if (!(m->flags & CMF_DISPLINE))
-				glines += 1 + (mlens[m->gnum] / columns);
-			} else if (!(m->flags & CMF_NOLIST))
-			    glines += 1 + ((1 + mlens[m->gnum]) / columns);
-		    }
-	    }
+	    g->lins = glines;
+	    nlines += glines;
 	}
-	g->lins = glines;
-	nlines += glines;
     }
-    if (isset(LISTPACKED)) {
+    if (!onlyexpl && isset(LISTPACKED)) {
 	char **pp;
 	int *ws, tlines, tline, tcols, maxlen, nth, width;
 
@@ -9017,6 +9125,9 @@ calclist(void)
     listdat.nlist = nlist;
     listdat.nlines = nlines;
     listdat.menuacc = menuacc;
+    listdat.onlyexpl = onlyexpl;
+    listdat.columns = columns;
+    listdat.lines = lines;
 }
 
 /**/
@@ -9111,7 +9222,7 @@ printlist(int over, CLPrintFunc printm)
 		e++;
 	    }
 	}
-	if (pp && *pp) {
+	if (!listdat.onlyexpl && pp && *pp) {
 	    if (pnl) {
 		putc('\n', shout);
 		pnl = 0;
@@ -9164,7 +9275,7 @@ printlist(int over, CLPrintFunc printm)
 		    pp += (isset(LISTROWSFIRST) ? g->cols : 1);
 		}
 	    }
-	} else if (g->lcount) {
+	} else if (!listdat.onlyexpl && g->lcount) {
 	    int n = g->dcount, nl, nc, i, j, wid;
 	    Cmatch *q;
 
@@ -9329,7 +9440,7 @@ int
 listlist(LinkList l)
 {
     struct cmgroup dg;
-    int vl = validlist, sm = smatches;
+    int vl = validlist, sm = smatches, nm = nmatches;
     char *oclp = complastprompt;
     Cmgroup am = amatches;
 
@@ -9341,12 +9452,14 @@ listlist(LinkList l)
     validlist = 1;
     memset(&dg, 0, sizeof(struct cmgroup));
     dg.ylist = (char **) makearray(l, 0, 1, &(dg.lcount), NULL, NULL);
+    nmatches = dg.lcount;
     amatches = &dg;
     ilistmatches(NULL, NULL);
     amatches = am;
 
     validlist = vl;
     smatches = sm;
+    nmatches = nm;
     complastprompt = oclp;
 
     return !dg.lcount;