about summary refs log tree commit diff
path: root/Src/Zle
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Zle')
-rw-r--r--Src/Zle/comp.h26
-rw-r--r--Src/Zle/comp1.c1
-rw-r--r--Src/Zle/comp1.export1
-rw-r--r--Src/Zle/compctl.c1
-rw-r--r--Src/Zle/complist.c42
-rw-r--r--Src/Zle/zle.export1
-rw-r--r--Src/Zle/zle_params.c25
-rw-r--r--Src/Zle/zle_refresh.c8
-rw-r--r--Src/Zle/zle_tricky.c162
9 files changed, 169 insertions, 98 deletions
diff --git a/Src/Zle/comp.h b/Src/Zle/comp.h
index 8264890df..b0fbf3ac6 100644
--- a/Src/Zle/comp.h
+++ b/Src/Zle/comp.h
@@ -218,6 +218,8 @@ struct cmatch {
     int brsl;			/* ...and the suffix */
     char *rems;			/* when to remove the suffix */
     char *remf;			/* shell function to call for suffix-removal */
+    int qipl;			/* length of quote-prefix */
+    int qisl;			/* length of quote-suffix */
     int rnum;			/* group relative number */
     int gnum;			/* global number */
 };
@@ -349,25 +351,25 @@ struct chdata {
 
 
 #define CPN_NMATCHES   0
-#define CP_NMATCHES    (1 <<  CPN_NMATCHES)
+#define CP_NMATCHES    (1 << CPN_NMATCHES)
 #define CPN_MATCHER    1
-#define CP_MATCHER     (1 <<  CPN_MATCHER)
+#define CP_MATCHER     (1 << CPN_MATCHER)
 #define CPN_MATCHERSTR 2
-#define CP_MATCHERSTR  (1 <<  CPN_MATCHERSTR)
+#define CP_MATCHERSTR  (1 << CPN_MATCHERSTR)
 #define CPN_MATCHERTOT 3
-#define CP_MATCHERTOT  (1 <<  CPN_MATCHERTOT)
+#define CP_MATCHERTOT  (1 << CPN_MATCHERTOT)
 #define CPN_CONTEXT    4
-#define CP_CONTEXT     (1 <<  CPN_CONTEXT)
+#define CP_CONTEXT     (1 << CPN_CONTEXT)
 #define CPN_PARAMETER  5
-#define CP_PARAMETER   (1 <<  CPN_PARAMETER)
+#define CP_PARAMETER   (1 << CPN_PARAMETER)
 #define CPN_REDIRECT   6
-#define CP_REDIRECT    (1 <<  CPN_REDIRECT)
+#define CP_REDIRECT    (1 << CPN_REDIRECT)
 #define CPN_QUOTE      7
-#define CP_QUOTE       (1 <<  CPN_QUOTE)
+#define CP_QUOTE       (1 << CPN_QUOTE)
 #define CPN_QUOTING    8
-#define CP_QUOTING     (1 <<  CPN_QUOTING)
+#define CP_QUOTING     (1 << CPN_QUOTING)
 #define CPN_RESTORE    9
-#define CP_RESTORE     (1 <<  CPN_RESTORE)
+#define CP_RESTORE     (1 << CPN_RESTORE)
 #define CPN_LIST       10
 #define CP_LIST        (1 << CPN_LIST)
 #define CPN_FORCELIST  11
@@ -398,6 +400,8 @@ 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 CP_KEYPARAMS   25
+#define CP_KEYPARAMS   26
 #define CP_ALLKEYS     ((unsigned int) 0xffffff)
diff --git a/Src/Zle/comp1.c b/Src/Zle/comp1.c
index ba8bcc868..c1e2bfb57 100644
--- a/Src/Zle/comp1.c
+++ b/Src/Zle/comp1.c
@@ -105,6 +105,7 @@ int incompfunc;
 /**/
 zlong compcurrent,
       compnmatches,
+      compnnmatches,
       compmatcher,
       compmatchertot,
       complistmax;
diff --git a/Src/Zle/comp1.export b/Src/Zle/comp1.export
index 9b738cc78..4b6dd92fd 100644
--- a/Src/Zle/comp1.export
+++ b/Src/Zle/comp1.export
@@ -27,6 +27,7 @@ compmatcher
 compmatcherstr
 compmatchertot
 compnmatches
+compnnmatches
 compoldlist
 compoldins
 compparameter
diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c
index 694af8429..e9ff83387 100644
--- a/Src/Zle/compctl.c
+++ b/Src/Zle/compctl.c
@@ -2210,6 +2210,7 @@ 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 },
     { NULL, 0, NULL, NULL, NULL }
 };
 
diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c
index 0e7152866..4bf3fec0e 100644
--- a/Src/Zle/complist.c
+++ b/Src/Zle/complist.c
@@ -308,8 +308,8 @@ complistmatches(Hookdef dummy, Chdata dat)
     Cmatch *p, m;
     Cexpl *e;
     int nlines = 0, ncols, nlist = 0, longest = 1, pnl = 0, opl = 0;
-    int of = isset(LISTTYPES);
-    int mc, ml = 0, cc, hasm = 0, cl;
+    int of = isset(LISTTYPES), cf;
+    int mc, ml = 0, cc, hasm = 0, cl = -1;
     struct listcols col;
 
     if (minfo.asked == 2) {
@@ -318,15 +318,6 @@ complistmatches(Hookdef dummy, Chdata dat)
     }
     getcols(&col);
 
-    /* Set the cursor below the prompt. */
-    if (inselect)
-	clearflag = 0;
-    trashzle();
-    showinglist = listshown = 0;
-
-    clearflag = (isset(USEZLE) && !termflags &&
-		 complastprompt && *complastprompt);
-
     for (g = amatches; g; g = g->next) {
 	char **pp = g->ylist;
 	int nl = 0, l;
@@ -403,6 +394,19 @@ complistmatches(Hookdef dummy, Chdata dat)
 			nlines += 1 + ((1 + niceztrlen(m->str)) / columns);
 	}
     }
+    cf = (isset(USEZLE) && !termflags && complastprompt && *complastprompt);
+    if (!nlines || (mselect >= 0 && (!cf || (nlines + nlnct - 1) >= lines))) {
+	showinglist = listshown = 0;
+	noselect = 1;
+	return 1;
+    }
+    /* Set the cursor below the prompt. */
+    if (inselect)
+	clearflag = 0;
+    trashzle();
+    showinglist = listshown = 0;
+
+    clearflag = cf;
 
     /* Maybe we have to ask if the user wants to see the list. */
     if ((!minfo.cur || !minfo.asked) &&
@@ -654,20 +658,20 @@ complistmatches(Hookdef dummy, Chdata dat)
 	    pnl = 1;
 	g = g->next;
     }
-
     if (clearflag) {
 	/* Move the cursor up to the prompt, if always_last_prompt *
 	 * is set and all that...                                  */
 	if ((nlines += nlnct - 1) < lines) {
 	    tcmultout(TCUP, TCMULTUP, nlines);
 	    showinglist = -1;
-	    listshown = 1;
 	} else
 	    clearflag = 0, putc('\n', shout);
     } else
 	putc('\n', shout);
+    listshown = (clearflag ? 1 : -1);
     if (!hasm || nlines >= lines)
 	noselect = 1;
+
     return noselect;
 }
 
@@ -676,7 +680,7 @@ typedef struct menustack *Menustack;
 struct menustack {
     Menustack prev;
     char *line;
-    int cs;
+    int cs, acc;
     struct menuinfo info;
     Cmgroup amatches, pmatches, lmatches;
 };
@@ -742,19 +746,19 @@ domenuselect(Hookdef dummy, Chdata dat)
 	    s->amatches = amatches;
 	    s->pmatches = pmatches;
 	    s->lmatches = lmatches;
-	    menucmp = 0;
+	    s->acc = menuacc;
+	    menucmp = menuacc = 0;
 	    fixsuffix();
 	    validlist = 0;
 	    pmatches = NULL;
 	    invalidatelist();
 	    menucomplete(zlenoargs);
 	    if (dat->num < 2 || !minfo.cur || !*(minfo.cur)) {
-		noselect = 1;
-		clearlist = 1;
+		noselect = clearlist = listshown = 1;
 		zrefresh();
 		break;
 	    }
-	    clearlist = 1;
+	    clearlist = listshown = 1;
 	    mselect = (*(minfo.cur))->gnum;
 	    continue;
 	} else if (cmd == Th(z_acceptandhold) ||
@@ -767,6 +771,7 @@ domenuselect(Hookdef dummy, Chdata dat)
 	    s->cs = cs;
 	    memcpy(&(s->info), &minfo, sizeof(struct menuinfo));
 	    s->amatches = s->pmatches = s->lmatches = NULL;
+	    s->acc = menuacc;
 	    acceptlast();
 	    do_menucmp(0);
 	    mselect = (*(minfo.cur))->gnum;
@@ -782,6 +787,7 @@ domenuselect(Hookdef dummy, Chdata dat)
 	    spaceinline(l = strlen(u->line));
 	    strncpy((char *) line, u->line, l);
 	    cs = u->cs;
+	    menuacc = u->acc;
 	    memcpy(&minfo, &(u->info), sizeof(struct menuinfo));
 	    p = &(minfo.cur);
 	    if (u->pmatches && pmatches != u->pmatches) {
diff --git a/Src/Zle/zle.export b/Src/Zle/zle.export
index 8bc049e16..f63f45eb8 100644
--- a/Src/Zle/zle.export
+++ b/Src/Zle/zle.export
@@ -24,6 +24,7 @@ lastambig
 linkkeymap
 listshown
 lmatches
+menuacc
 menucmp
 menucomplete
 menucur
diff --git a/Src/Zle/zle_params.c b/Src/Zle/zle_params.c
index dc4e27685..5ed846cd6 100644
--- a/Src/Zle/zle_params.c
+++ b/Src/Zle/zle_params.c
@@ -67,7 +67,7 @@ static struct zleparam {
         zleunsetfn, NULL },
     { "LASTWIDGET", PM_SCALAR | PM_READONLY, NULL, FN(get_lwidget),
         zleunsetfn, NULL },
-    { "keys", PM_ARRAY | PM_READONLY, NULL, FN(get_keys),
+    { "KEYS", PM_SCALAR | PM_READONLY, NULL, FN(get_keys),
         zleunsetfn, NULL },
     { "NUMERIC", PM_INTEGER | PM_UNSET, FN(set_numeric), FN(get_numeric),
         unset_numeric, NULL },
@@ -247,29 +247,10 @@ get_lwidget(Param pm)
 }
 
 /**/
-static char **
+static char *
 get_keys(Param pm)
 {
-    char **r, **q, *p, *k, c;
-
-    r = (char **) zhalloc((strlen(keybuf) + 1) * sizeof(char *));
-    for (q = r, p = keybuf; (c = *p); q++, p++) {
-	k = *q = (char *) zhalloc(5);
-	if (c & 0x80) {
-	    *k++ = 'M';
-	    *k++ = '-';
-	    c &= 0x7f;
-	}
-	if (c < 32 || c == 0x7f) {
-	    *k++ = '^';
-	    c ^= 64;
-	}
-	*k++ = c;
-	*k = '\0';
-    }
-    *q = NULL;
-
-    return r;
+    return keybuf;
 }
 
 /**/
diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c
index 48e1071b8..1dbffc21c 100644
--- a/Src/Zle/zle_refresh.c
+++ b/Src/Zle/zle_refresh.c
@@ -53,7 +53,8 @@ int nlnct;
 /**/
 int showinglist;
 
-/* Non-zero if a completion list was displayed. */
+/* > 0 if a completion list is displayed below the prompt,
+ * < 0 if a list is displayed above the prompt. */
 
 /**/
 int listshown;
@@ -265,7 +266,7 @@ zrefresh(void)
     if (inlist)
 	return;
 
-    if (clearlist && listshown) {
+    if (clearlist && listshown > 0) {
 	if (tccan(TCCLEAREOD)) {
 	    int ovln = vln, ovcs = vcs;
 	    char *nb = nbuf[vln];
@@ -331,7 +332,8 @@ zrefresh(void)
                 tcout(TCCLEAREOD);
             else
                 cleareol = 1;   /* request: clear to end of line */
-	    listshown = 0;
+	    if (listshown > 0)
+		listshown = 0;
 	}
         if (t0 > -1)
             olnct = t0;
diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index 5461079cb..b678a5cad 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -106,10 +106,11 @@ static int insmnum, insgnum, insgroup, insspace;
 
 static int movetoend;
 
-/* != 0 if we are in the middle of a menu completion */
+/* != 0 if we are in the middle of a menu completion and number of matches
+* accepted with accept-and-menu-complete */
 
 /**/
-int menucmp;
+int menucmp, menuacc;
 
 /* Information about menucompletion. */
 
@@ -192,6 +193,10 @@ static char *qipre, *qisuf, autoq;
 static int lpl, lsl, rpl, rsl, fpl, fsl, lppl, lpsl;
 static int noreal;
 
+/* A parameter expansion prefix (like ${). */
+
+static char *parpre;
+
 /* This is either zero or equal to the special character the word we are *
  * trying to complete starts with (e.g. Tilde or Equals).                */
 
@@ -209,9 +214,9 @@ static char *qword;
 
 static Cmgroup mgroup;
 
-/* A match counter. */
+/* Match counters: all matches, normal matches (not alternate set). */
 
-static int mnum;
+static int mnum, nmnum;
 
 /* The match counter when unambig_data() was called. */
 
@@ -540,6 +545,8 @@ reversemenucomplete(char **args)
 void
 acceptlast(void)
 {
+    menuacc++;
+
     if (brbeg && *brbeg) {
 	int l;
 
@@ -553,10 +560,16 @@ acceptlast(void)
 	brbeg[l] = ',';
 	brbeg[l + 1] = '\0';
     } else {
+	int l;
+
 	cs = minfo.pos + minfo.len + minfo.insc;
 	iremovesuffix(' ', 1);
-
+	l = cs;
+	cs = minfo.pos + minfo.len - (*(minfo.cur))->qisl;
+	foredel(l - cs);
 	inststrlen(" ", 1, 1);
+	if (parpre)
+	    inststr(parpre);
 	minfo.insc = minfo.len = 0;
 	minfo.pos = cs;
 	minfo.we = 1;
@@ -694,6 +707,9 @@ check_param(char *s, int set, int test)
 {
     char *p;
 
+    zsfree(parpre);
+    parpre = NULL;
+
     if (!test)
 	ispar = parq = eparq = 0;
     /* Try to find a `$'. */
@@ -755,6 +771,8 @@ check_param(char *s, int set, int test)
 
 	/* Now make sure that the cursor is inside the name. */
 	if (offs <= e - s && offs >= b - s && n <= 0) {
+	    char sav;
+
 	    if (br) {
 		p = e;
 		while (*p == (test ? Dnull : '"'))
@@ -782,6 +800,12 @@ check_param(char *s, int set, int test)
 	    else
 		parq = eparq = 0;
 
+	    /* Save the prefix. */
+	    sav = *b;
+	    *b = '\0';
+	    untokenize(parpre = ztrdup(s));
+	    *b = sav;
+
 	    /* And adjust wb, we, and offs again. */
 	    offs -= b - s;
 	    wb = cs - offs;
@@ -1017,7 +1041,7 @@ docomplete(int lst)
 	    int ocs = cs, ne = noerrs;
 
 	    noerrs = 1;
-	    doexpansion(s, lst, olst, lincmd);
+	    ret = doexpansion(s, lst, olst, lincmd);
 	    lastambig = 0;
 	    noerrs = ne;
 
@@ -1043,8 +1067,8 @@ docomplete(int lst)
 			}
 		}
 		ret = docompletion(s, lst, lincmd);
-	    } else
-		ret = !strcmp(ol, (char *) line);
+	    } else if (ret)
+		clearlist = 1;
 	} else
 	    /* Just do completion. */
 	    ret = docompletion(s, lst, lincmd);
@@ -1064,7 +1088,7 @@ docomplete(int lst)
 	dat.num = nmatches;
 	dat.cur = NULL;
 	if (runhookdef(MENUSTARTHOOK, (void *) &dat))
-	    menucmp = 0;
+	    menucmp = menuacc = 0;
     }
     return ret;
 }
@@ -1736,9 +1760,10 @@ get_comp_string(void)
 /* Expand the current word. */
 
 /**/
-static void
+static int
 doexpansion(char *s, int lst, int olst, int explincmd)
 {
+    int ret = 1;
     LinkList vl;
     char *ss;
 
@@ -1775,7 +1800,7 @@ doexpansion(char *s, int lst, int olst, int explincmd)
 	}
 	if (lst == COMP_LIST_EXPAND) {
 	    /* Only the list of expansions was requested. */
-	    listlist(vl);
+	    ret = listlist(vl);
 	    showinglist = 0;
 	    goto end;
 	}
@@ -1783,6 +1808,7 @@ doexpansion(char *s, int lst, int olst, int explincmd)
 	cs = wb;
 	foredel(we - wb);
 	while ((ss = (char *)ugetnode(vl))) {
+	    ret = 0;
 	    untokenize(ss);
 	    ss = quotename(ss, NULL);
 	    inststr(ss);
@@ -1801,6 +1827,8 @@ doexpansion(char *s, int lst, int olst, int explincmd)
       end:
 	popheap();
     } LASTALLOC;
+
+    return ret;
 }
 
 /* This is called from the lexer to give us word positions. */
@@ -3547,6 +3575,8 @@ 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. */
@@ -3569,6 +3599,8 @@ add_match_data(int alt, char *str, Cline line,
     cm->flags = flags;
     cm->brpl = bpl;
     cm->brsl = bsl;
+    cm->qipl = qipl;
+    cm->qisl = qisl;
     cm->autoq = (autoq ? autoq : (inbackt ? '`' : '\0'));
     cm->rems = cm->remf = NULL;
     addlinknode((alt ? fmatches : matches), cm);
@@ -3896,6 +3928,7 @@ addmatches(Cadata dat, char **argv)
 		}
 	    }
 	    compnmatches = mnum;
+	    compnnmatches = nmnum;
 	    if (dat->exp)
 		addexpl();
 	    if (dat->apar)
@@ -4380,10 +4413,14 @@ docompletion(char *s, int lst, int incmd)
 	}
 	if (comppatmatch && *comppatmatch && comppatmatch != opm)
 	    haspattern = 1;
-	if (!useline && uselist)
+	if (!useline && uselist) {
 	    /* All this and the guy only wants to see the list, sigh. */
+	    cs = 0;
+	    foredel(ll);
+	    inststr(origline);
+	    cs = origcs;
 	    showinglist = -2;
-	else if (useline) {
+	} else if (useline) {
 	    /* We have matches. */
 	    if (nmatches > 1) {
 		/* There is more than one match. */
@@ -4399,9 +4436,13 @@ docompletion(char *s, int lst, int incmd)
 		do_single(m->matches[0]);
 		invalidatelist();
 	    }
-	} else
+	} else {
 	    invalidatelist();
-
+	    cs = 0;
+	    foredel(ll);
+	    inststr(origline);
+	    cs = origcs;
+	}
 	/* Print the explanation strings if needed. */
 	if (!showinglist && validlist && usemenu != 2 && nmatches != 1) {
 	    Cmgroup g = amatches;
@@ -4582,22 +4623,22 @@ callcompfunc(char *s, char *fn)
 	zsfree(compprefix);
 	zsfree(compsuffix);
 	if (unset(COMPLETEINWORD)) {
-	    /* Maybe we'll have to do quoting here some time. */
-	    tmp = dupstring(s);
+	    tmp = quotename(s, NULL);
 	    untokenize(tmp);
 	    compprefix = ztrdup(tmp);
 	    compsuffix = ztrdup("");
 	} else {
 	    char *ss, sav;
 	    
-	    tmp = dupstring(s);
-	    ss = tmp + offs;
+	    ss = s + offs;
 
 	    sav = *ss;
 	    *ss = '\0';
+	    tmp = quotename(s, NULL);
 	    untokenize(tmp);
 	    compprefix = ztrdup(tmp);
 	    *ss = sav;
+	    ss = quotename(ss, NULL);
 	    untokenize(ss);
 	    compsuffix = ztrdup(ss);
 	}
@@ -4611,6 +4652,7 @@ callcompfunc(char *s, char *fn)
 	compqisuffix = ztrdup(qisuf ? qisuf : "");
 	compcurrent = (usea ? (clwpos + 1 - aadd) : 0);
 	compnmatches = mnum;
+	compnnmatches = nmnum;
 
 	zsfree(complist);
 	switch (uselist) {
@@ -4825,13 +4867,13 @@ makecomplist(char *s, int incmd, int lst)
 	if (!validlist)
 	    lastambig = 0;
 	amatches = NULL;
-	mnum = 0;
+	mnum = nmnum = 0;
 	unambig_mnum = -1;
 	isuf = NULL;
 	insmnum = insgnum = 1;
 	insgroup = oldlist = oldins = 0;
 	begcmgroup("default", 0);
-	menucmp = 0;
+	menucmp = menuacc = 0;
 
 	ccused = newlinklist();
 	ccstack = newlinklist();
@@ -4984,6 +5026,8 @@ sep_comp_string(char *ss, char *s, int noffs, int rec)
     memcpy(tmp + sl + 1, s, noffs);
     tmp[(scs = cs = sl + 1 + noffs)] = 'x';
     strcpy(tmp + sl + 2 + noffs, s + noffs);
+    if (incompfunc)
+	tmp = rembslash(tmp);
     inpush(dupstrspace(tmp), 0, NULL);
     line = (unsigned char *) tmp;
     ll = tl - 1;
@@ -5013,6 +5057,7 @@ sep_comp_string(char *ss, char *s, int noffs, int rec)
 	    p = NULL;
 	if (!got && !zleparse) {
 	    DPUTS(!p, "no current word in substr");
+	    got = 1;
 	    cur = i;
 	    swb = wb - 1;
 	    swe = we - 1;
@@ -5077,7 +5122,7 @@ sep_comp_string(char *ss, char *s, int noffs, int rec)
     }
     sav = s[(i = swb - sl - 1)];
     s[i] = '\0';
-    qp = tricat(qipre, s, "");
+    qp = tricat(qipre, (incompfunc ? rembslash(s) : s), "");
     s[i] = sav;
     if (swe < swb)
 	swe = swb;
@@ -5085,7 +5130,7 @@ sep_comp_string(char *ss, char *s, int noffs, int rec)
     sl = strlen(s);
     if (swe > sl)
 	swe = sl, ns[swe - swb + 1] = '\0';
-    qs = tricat(s + swe, qisuf, "");
+    qs = tricat((incompfunc ? rembslash(s + swe) : s + swe), qisuf, "");
     sl = strlen(ns);
     if (soffs > sl)
 	soffs = sl;
@@ -5172,7 +5217,7 @@ sep_comp_string(char *ss, char *s, int noffs, int rec)
 	compisuffix = ztrdup("");
 	zsfree(compqiprefix);
 	zsfree(compqisuffix);
-	if (instring) {
+	if (ois) {
 	    compqiprefix = qp;
 	    compqisuffix = qs;
 	} else {
@@ -5188,6 +5233,7 @@ sep_comp_string(char *ss, char *s, int noffs, int rec)
 	    p = compwords[i] = (char *) getdata(n);
 	    untokenize(p);
 	}
+	compcurrent = cur + 1;
 	compwords[i] = NULL;
     }
     autoq = oaq;
@@ -5242,6 +5288,7 @@ makecomplistcall(Compctl cc)
 	    inbackt = oib;
 	    autoq = oaq;
 	    compnmatches = mnum;
+	    compnnmatches = nmnum;
 	} LASTALLOC;
     } SWITCHBACKHEAPS;
 
@@ -5317,6 +5364,7 @@ makecomplistctl(int flags)
 	    autoq = oaq;
 	    offs = ooffs;
 	    compnmatches = mnum;
+	    compnnmatches = nmnum;
 	    zsfree(cmdstr);
 	    freearray(clwords);
 	    cmdstr = os;
@@ -5979,7 +6027,10 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	    char save = line[cs];
 
 	    line[cs] = 0;
-	    lppre = dupstring((char *) (line + wb));
+	    lppre = dupstring((char *) line + wb +
+			      (qipre && *qipre ?
+			       (strlen(qipre) -
+				(*qipre == '\'' || *qipre == '\"')) : 0));
 	    line[cs] = save;
 	    if (brbeg && *brbeg)
 		strcpy(lppre + qbrpl, lppre + qbrpl + strlen(brbeg));
@@ -5998,11 +6049,17 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	    lppl = 0;
 	}
 	if (cs != we) {
-	    char save = line[we];
+	    int end = we;
+	    char save = line[end];
+
+	    if (qisuf && *qisuf) {
+		int ql = strlen(qisuf);
 
-	    line[we] = 0;
+		end -= ql - (qisuf[ql-1] == '\'' || qisuf[ql-1] == '"');
+	    }
+	    line[end] = 0;
 	    lpsuf = dupstring((char *) (line + cs));
-	    line[we] = save;
+	    line[end] = save;
 	    if (brend && *brend) {
 		char *p = lpsuf + qbrsl - (cs - wb);
 
@@ -6640,7 +6697,8 @@ invalidatelist(void)
 	listmatches();
     if (validlist)
 	freematches();
-    lastambig = menucmp = validlist = showinglist = fromcomp = 0;
+    lastambig = menucmp = menuacc = validlist = showinglist =
+	fromcomp = listshown = 0;
     minfo.cur = NULL;
     minfo.asked = 0;
     compwidget = NULL;
@@ -6917,6 +6975,8 @@ dupmatch(Cmatch m)
     r->rems = ztrdup(m->rems);
     r->remf = ztrdup(m->remf);
     r->autoq = m->autoq;
+    r->qipl = m->qipl;
+    r->qisl = m->qisl;
 
     return r;
 }
@@ -7346,7 +7406,9 @@ instmatch(Cmatch m, int *scs)
 
     /* Ignored prefix. */
     if (m->ipre) {
-	inststrlen(m->ipre, 1, (l = strlen(m->ipre)));
+	char *p = m->ipre + (menuacc ? m->qipl : 0);
+
+	inststrlen(p, 1, (l = strlen(p)));
 	r += l;
     }
     /* -P prefix. */
@@ -7413,7 +7475,8 @@ static int
 do_ambiguous(void)
 {
     int ret = 0;
-    menucmp = 0;
+
+    menucmp = menuacc = 0;
 
     /* If we have to insert the first match, call do_single().  This is *
      * how REC_EXACT takes effect.  We effectively turn the ambiguous   *
@@ -7501,11 +7564,13 @@ do_ambiguous(void)
      * if it is needed.                                                     */
     if (isset(LISTBEEP))
 	ret = 1;
-    if (uselist && (usemenu != 2 || (!showinglist && !oldlist)) &&
+
+    if (uselist && (usemenu != 2 || (!listshown && !oldlist)) &&
 	((!showinglist && (!listshown || !oldlist)) ||
 	 (usemenu == 3 && !oldlist)) &&
 	(smatches >= 2 || (compforcelist && *compforcelist)))
 	showinglist = -2;
+
     return ret;
 }
 
@@ -7649,7 +7714,7 @@ do_single(Cmatch m)
 	    }
 	}
 	if (!minfo.insc)
-	    cs = minfo.pos + minfo.len;
+	    cs = minfo.pos + minfo.len - m->qisl;
     }
     /* If completing in a brace expansion... */
     if (brbeg) {
@@ -7688,8 +7753,11 @@ do_single(Cmatch m)
     if (minfo.we && m->ripre && isset(AUTOPARAMKEYS))
 	makeparamsuffix(((m->flags & CMF_PARBR) ? 1 : 0), minfo.insc - parq);
 
-    if ((menucmp && !minfo.we) || !movetoend)
+    if ((menucmp && !minfo.we) || !movetoend) {
 	cs = minfo.end;
+	if (cs + m->qisl == lastend)
+	    cs += minfo.insc;
+    }
     {
 	Cmatch *om = minfo.cur;
 	struct chdata dat;
@@ -7732,6 +7800,7 @@ do_ambig_menu(void)
 
     if (usemenu != 3) {
 	menucmp = 1;
+	menuacc = 0;
 	minfo.cur = NULL;
     } else {
 	if (oldlist) {
@@ -7931,13 +8000,6 @@ ilistmatches(Hookdef dummy, Chdata dat)
     int nlines = 0, ncols, nlist = 0, longest = 1, pnl = 0;
     int of = isset(LISTTYPES), opl = 0;
 
-    /* Set the cursor below the prompt. */
-    trashzle();
-    showinglist = listshown = 0;
-
-    clearflag = (isset(USEZLE) && !termflags &&
-		 complastprompt && *complastprompt);
-
     for (g = amatches; g; g = g->next) {
 	char **pp = g->ylist;
 	int nl = 0, l;
@@ -8013,6 +8075,16 @@ ilistmatches(Hookdef dummy, Chdata dat)
 			nlines += 1 + ((1 + niceztrlen(m->str)) / columns);
 	}
     }
+    if (!nlines) {
+	showinglist = listshown = 0;
+	return 1;
+    }
+    /* Set the cursor below the prompt. */
+    trashzle();
+    showinglist = listshown = 0;
+
+    clearflag = (isset(USEZLE) && !termflags &&
+		 complastprompt && *complastprompt);
 
     /* Maybe we have to ask if the user wants to see the list. */
     if ((!minfo.cur || !minfo.asked) &&
@@ -8152,25 +8224,25 @@ ilistmatches(Hookdef dummy, Chdata dat)
 	    pnl = 1;
 	g = g->next;
     }
-
     if (clearflag) {
 	/* Move the cursor up to the prompt, if always_last_prompt *
 	 * is set and all that...                                  */
 	if ((nlines += nlnct - 1) < lines) {
 	    tcmultout(TCUP, TCMULTUP, nlines);
 	    showinglist = -1;
-	    listshown = 1;
 	} else
 	    clearflag = 0, putc('\n', shout);
     } else
 	putc('\n', shout);
+    listshown = (clearflag ? 1 : -1);
+
     return 0;
 }
 
 /* This is used to print expansions. */
 
 /**/
-void
+int
 listlist(LinkList l)
 {
     struct cmgroup dg;
@@ -8193,6 +8265,8 @@ listlist(LinkList l)
     validlist = vl;
     smatches = sm;
     complastprompt = oclp;
+
+    return !dg.lcount;
 }
 
 /* Expand the history references. */