about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSven Wischnowsky <wischnow@users.sourceforge.net>2000-10-11 12:19:23 +0000
committerSven Wischnowsky <wischnow@users.sourceforge.net>2000-10-11 12:19:23 +0000
commitadf79659510ed08c78bb4ccb881a5c03ef2e6759 (patch)
tree8d2388a2435c7648b253a01d130be5ce1146419c
parent5d8adbee0753795e7903b40847e17c879766dbf7 (diff)
downloadzsh-adf79659510ed08c78bb4ccb881a5c03ef2e6759.tar.gz
zsh-adf79659510ed08c78bb4ccb881a5c03ef2e6759.tar.xz
zsh-adf79659510ed08c78bb4ccb881a5c03ef2e6759.zip
add _all_matcher completer and supporting C-code for adding a special match representing all other matches; remove completions style from _expand(|_word) (12960)
-rw-r--r--ChangeLog8
-rw-r--r--Completion/Builtins/_zstyle13
-rw-r--r--Completion/Commands/_expand_word11
-rw-r--r--Completion/Core/_all_matches43
-rw-r--r--Completion/Core/_expand8
-rw-r--r--Doc/Zsh/compsys.yo74
-rw-r--r--Doc/Zsh/compwid.yo11
-rw-r--r--Src/Zle/comp.h2
-rw-r--r--Src/Zle/compcore.c83
-rw-r--r--Src/Zle/complete.c5
-rw-r--r--Src/Zle/complist.c4
-rw-r--r--Src/Zle/compresult.c164
12 files changed, 318 insertions, 108 deletions
diff --git a/ChangeLog b/ChangeLog
index b11938045..b14c3f540 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 2000-10-11  Sven Wischnowsky  <wischnow@zsh.org>
 
+	* 12960: Completion/Builtins/_zstyle, Completion/Commands/_expand_word,
+ 	Completion/Core/_all_matches, Completion/Core/_expand,
+ 	Doc/Zsh/compsys.yo, Doc/Zsh/compwid.yo, Src/Zle/comp.h,
+ 	Src/Zle/compcore.c, Src/Zle/complete.c, Src/Zle/complist.c,
+ 	Src/Zle/compresult.c:add _all_matcher completer and supporting
+ 	C-code for adding a special match representing all other matches;
+ 	remove completions style from _expand(|_word)
+	
 	* 12959: Src/Zle/compcore.c, Src/Zle/complist.c: make user defined
  	completion widgets leave menu selection without accepting the
  	currently selected match
diff --git a/Completion/Builtins/_zstyle b/Completion/Builtins/_zstyle
index 62e5369e4..21c6fd0de 100644
--- a/Completion/Builtins/_zstyle
+++ b/Completion/Builtins/_zstyle
@@ -58,7 +58,8 @@ styles=(
   max-errors		 c:
   menu			 c:boolauto
   numbers		 c:bool
-  old-list		 c:bool 
+  old-list		 c:bool
+  old-matches            c:oldmatches
   old-menu		 c:bool 
   original		 c:bool
   packageset		 c:packageset
@@ -275,15 +276,19 @@ while [[ -n $state ]]; do
       ;;
 
     ignline) 
-      _wanted values expl boolean compadd true false current current-shown other
+      _wanted values expl 'ignore strings on the line' compadd true false current current-shown other
       ;;
 
     keep-prefix) 
-      _wanted values expl boolean compadd true false changed
+      _wanted values expl 'keep prefix' compadd true false changed
       ;;
 
     match-orig) 
-      _wanted values expl boolean compadd only both
+      _wanted values expl "match without inserting \`*'" compadd only both
+      ;;
+
+    oldmatches) 
+      _wanted values expl 'use list of old matches' compadd true false only
       ;;
 
     urgh) 
diff --git a/Completion/Commands/_expand_word b/Completion/Commands/_expand_word
index 3ec3cc756..895695676 100644
--- a/Completion/Commands/_expand_word
+++ b/Completion/Commands/_expand_word
@@ -6,7 +6,6 @@ setopt localoptions nullglob rcexpandparam extendedglob unset
 unsetopt markdirs globsubst shwordsplit shglob ksharrays cshnullglob
 
 local curcontext="$curcontext"
-local -ah completers
 
 if [[ -z "$curcontext" ]]; then
   curcontext="expand-word:::"
@@ -14,12 +13,4 @@ else
   curcontext="expand-word:${curcontext#*:}"
 fi
 
-if zstyle -t ":completion:${curcontext}:" completions; then
-    zstyle -a ":completion:${curcontext}:" completer completers
-    completers[1,(i)_expand]=_expand
-    (( $#completers == 1 )) && completers=(_expand _complete)
-else
-    completers=(_expand)
-fi
-
-_main_complete $completers
+_main_complete _expand
diff --git a/Completion/Core/_all_matches b/Completion/Core/_all_matches
new file mode 100644
index 000000000..f33d78040
--- /dev/null
+++ b/Completion/Core/_all_matches
@@ -0,0 +1,43 @@
+#autoload
+
+_all_matches() {
+  local old
+
+  zstyle -s ":completion:${curcontext}:" old-matches old
+
+  if [[ "$old" = (only|true|yes|1|on) ]]; then
+
+    if [[ -n "$compstate[old_list]" ]]; then
+      compstate[insert]=all
+      compstate[old_list]=keep
+      return 0
+    fi
+
+    [[ "$old" = *only* ]] && return 1
+  fi
+
+  (( $comppostfuncs[(I)_all_matches_end] )) ||
+      comppostfuncs=( "$comppostfuncs[@]" _all_matches_end )
+
+  _all_matches_context=":completion:${curcontext}:"
+
+  return 1
+}
+
+_all_matches_end() {
+  local not
+
+  zstyle -s "$_all_matches_context" avoid-completer not ||
+      not=( _expand _old_list _correct _approximate )
+
+  if [[ "$compstate[nmatches]" -gt 1 && $not[(I)(|_)$_completer] -eq 0 ]]; then
+    local expl
+
+    _description all-matches expl 'all matches'
+    compadd "$expl[@]" -C
+  fi
+
+  unset _all_matches_context
+}
+
+_all_matches "$@"
diff --git a/Completion/Core/_expand b/Completion/Core/_expand
index f0e12cb99..344dbaf88 100644
--- a/Completion/Core/_expand
+++ b/Completion/Core/_expand
@@ -18,14 +18,6 @@ local exp word sort expr expl subd suf=" " force opt asp tmp opre pre epre
       force="$force$opt"
     done
 
-# First, see if we should insert all *completions*.
-
-if [[ "$force" = *c* ]] ||
-   zstyle -t ":completion:${curcontext}:" completions; then
-  compstate[insert]=all
-  return 1
-fi
-
 if [[ "$funcstack[2]" = _prefix ]]; then
   word="$IPREFIX$PREFIX$SUFFIX"
 else
diff --git a/Doc/Zsh/compsys.yo b/Doc/Zsh/compsys.yo
index 11837cb49..0b1e9fda3 100644
--- a/Doc/Zsh/compsys.yo
+++ b/Doc/Zsh/compsys.yo
@@ -901,6 +901,18 @@ the description for this argument.  Depending on personal preferences,
 it may be useful to set this style to something like `tt(specify: %d)'. 
 Note that this may not work for some commands.
 )
+kindex(avoid-completer, completion style)
+item(tt(avoid-completer))(
+This is used by the tt(_all_matches) completer to decide if the string 
+consisting of all matches should be added to the list currently being
+generated.  Its value is a list of names of completers.  If any of
+these is the name of the completer that generated the matches in this
+completion, the string will not be added.
+
+The default value for this style is `tt(_expand _old_list _correct
+_approximate)', i.e. it contains the completers for which a string
+with all matches will almost never be wanted.
+)
 kindex(cache-path, completion style)
 item(tt(cache-path))(
 This style defines the path where any cache files containing dumped
@@ -966,14 +978,6 @@ i.e. normally only completion will be done, first using the
 tt(ignored-patterns) style and the tt($fignore) array and then without 
 ignoring matches.
 )
-kindex(completions, completion style)
-item(tt(completions))(
-This style is used by the tt(_expand) completer function. If it is set 
-to `true', the completer will not generate expansions, but instead the
-completions will be generated as normal and all of them will be
-inserted into the command line.  This style is most useful when set
-only for very specific completion contexts.
-)
 kindex(condition, completion style)
 item(tt(condition))(
 This style is used by the tt(_list) completer function to decide if
@@ -1159,7 +1163,7 @@ ifnzman(noderef(The zsh/zutil Module))\
 )
 kindex(glob, completion style)
 item(tt(glob))(
-Like tt(completions), this is used by the tt(_expand) completer.  If
+This is used by the tt(_expand) completer.  If
 it is set to `true' (the default), globbing will be attempted on the
 words resulting from substitution (see the tt(substitute) style) or
 the original string from the line.
@@ -1650,6 +1654,15 @@ first attempt.  By using the tt(_oldlist) completer and setting this style
 to tt(_match), the list of matches generated on the first attempt will be
 used again.
 )
+kindex(old-matches, completion style)
+item(tt(old-matches))(
+This is used by the tt(_all_matches) completer to decide if an old
+list of matches should be used if one exists.  It may be set to one of 
+the `true' values or to the string `tt(only)' to use such a list.  If
+it is set to `tt(only)', tt(_all_matches) will only use an old list
+and won't have any effect on the list of matches currently being
+generated.
+)
 kindex(old-menu, completion style)
 item(tt(old-menu))(
 This is used by the tt(_oldlist) completer.  It controls how menu
@@ -2109,6 +2122,34 @@ may write their own):
 
 cindex(completion system, completers)
 startitem()
+findex(_all_matches)
+item(tt(_all_matches))(
+This completer can be used to add a string consisting of all other
+matches.  To ensure, that this string is always added, this completer
+has to be used as the first completer in the list.  The
+tt(avoid-completer) style is used to decide if the string should be
+added.  This will only be done if the matches were generated by a
+completer not named by one of the values of the style.
+
+This function also uses the style tt(old-matches).  If it is set to
+`true' or to the string `tt(only)' and there is a list of matches from 
+a previous completion, those matches will be inserted in the command
+line.  If it is set to the the string `tt(only)', it will only insert
+an old list and won't add the string for all matches of the list
+currently being generated.
+
+With the tt(old-matches) style set, this completer should probably not 
+be called unconditionally.  Instead one could use the tt(-e) option of 
+the tt(zstyle) builtin command to add a condition to the tt(completer) 
+or to the tt(old-matches) style.  Alternatively, one could use the
+tt(_generic) function to bind tt(_all_matches) to a separate key
+binding, for example:
+
+example(zle -C all-matches complete-word _generic
+bindkey '^Xa' all-matches
+zstyle ':completion:all-matches:*' old-matches only
+zstyle ':completion:all-matches:*' completer _all_matches)
+)
 findex(_approximate)
 item(tt(_approximate))(
 This completer function uses the tt(_complete) completer to generate
@@ -2312,14 +2353,9 @@ string from the line.
 Which kind of expansion is tried is controlled by the tt(substitute),
 tt(glob) and tt(subst-globs-only) styles.
 
-There is another style, tt(completions), which causes tt(_expand) to
-unconditionally insert all em(completions) generated for the current
-word (even if the word is empty).
-
 When tt(_expand) is called as a function, the different modes may be
-selected with options.  The tt(-c) corresponds to the tt(completions)
-style, tt(-s) to tt(substitute), tt(-g) to tt(glob) and tt(-o) to
-tt(subst-globs-only).
+selected with options.  The tt(-s) to tt(substitute), tt(-g) to
+tt(glob) and tt(-o) to tt(subst-globs-only).
 )
 findex(_history)
 item(tt(_history))(
@@ -2495,12 +2531,6 @@ item(tt(_expand_word (^Xe)))(
 Performs expansion on the current word:  equivalent to the standard
 tt(expand-word) command, but using the tt(_expand) completer.  Before
 calling it, the var(function) field is set to `tt(expand-word)'.
-
-The tt(completions) style is also tested in the resulting context.  When
-it is true, the list of functions from the tt(completer) style is shifted
-to remove any that would be called ahead of tt(_expand).  If tt(_expand)
-does not appear in the tt(completer) style, then only the two completers
-tt(_expand) and tt(_complete) are used (in that order).
 )
 findex(_generic)
 item(tt(_generic))(
diff --git a/Doc/Zsh/compwid.yo b/Doc/Zsh/compwid.yo
index 5747e3d22..e793085af 100644
--- a/Doc/Zsh/compwid.yo
+++ b/Doc/Zsh/compwid.yo
@@ -418,7 +418,7 @@ sect(Builtin Commands)
 startitem()
 findex(compadd)
 cindex(completion widgets, adding specified matches)
-xitem(tt(compadd) [ tt(-akqQfenUl12) ] [ tt(-F) var(array) ])
+xitem(tt(compadd) [ tt(-akqQfenUl12C) ] [ tt(-F) var(array) ])
 xitem([ tt(-P) var(prefix) ] [ tt(-S) var(suffix) ])
 xitem([ tt(-p) var(hidden-prefix) ] [ tt(-s) var(hidden-suffix) ])
 xitem([ tt(-i) var(ignored-prefix) ] [ tt(-I) var(ignored-suffix) ])
@@ -640,6 +640,15 @@ in turn 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(-C))(
+This option adds a special match which expands to all other metches
+when inserted into the line, even those that are added after this
+option is used.  Together with the tt(-d) option it is possible to
+specify a string that should be displayed in the list for this special 
+match.  If no string is given, it will be shown as a string containing 
+the strings that would be inserted for the other matches, truncated to 
+the width of the screen.
+)
 xitem(tt(-))
 item(tt(-)tt(-))(
 This flag ends the list of flags and options. All arguments after it
diff --git a/Src/Zle/comp.h b/Src/Zle/comp.h
index 57091c744..b18947064 100644
--- a/Src/Zle/comp.h
+++ b/Src/Zle/comp.h
@@ -124,6 +124,7 @@ struct cmatch {
 #define CMF_ROWS     (1<<10)	/* prefer LIST_ROWS_FIRST */
 #define CMF_MULT     (1<<11)	/* string appears more than once */
 #define CMF_FMULT    (1<<12)	/* first of multiple equal strings */
+#define CMF_ALL      (1<<13)	/* a match representing all other matches */
 
 /* Stuff for completion matcher control. */
 
@@ -236,6 +237,7 @@ struct menuinfo {
 #define CAF_UNIQALL 16
 #define CAF_ARRAYS  32
 #define CAF_KEYS    64
+#define CAF_ALL    128
 
 /* Data for compadd and addmatches() */
 
diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c
index 6941dbfe2..fa8104169 100644
--- a/Src/Zle/compcore.c
+++ b/Src/Zle/compcore.c
@@ -143,6 +143,11 @@ mod_export Cmgroup lastmatches, pmatches, amatches, lmatches, lastlmatches;
 /**/
 mod_export int hasoldlist, hasperm;
 
+/* Non-zero if we have a match representing all other matches. */
+
+/**/
+int hasallmatch;
+
 /* Non-zero if we have newly added matches. */
 
 /**/
@@ -331,6 +336,7 @@ do_completion(Hookdef dummy, Compldat dat)
     maxmlen = -1;
     compignored = 0;
     nmessages = 0;
+    hasallmatch = 0;
 
     /* Make sure we have the completion list and compctl. */
     if (makecomplist(s, incmd, lst)) {
@@ -366,41 +372,8 @@ do_completion(Hookdef dummy, Compldat dat)
 	cs = origcs;
 	showinglist = -2;
     } else if (useline == 2 && nmatches > 1) {
-	int first = 1, nm = nmatches;
-	Cmatch *mc;
-
-	menucmp = 1;
-	menuacc = 0;
-
-	for (minfo.group = amatches;
-	     minfo.group && !(minfo.group)->mcount;
-	     minfo.group = (minfo.group)->next);
+	do_allmatches(1);
 
-	mc = (minfo.group)->matches;
-
-	while (1) {
-	    if (!first)
-		accept_last();
-	    first = 0;
-
-	    if (!--nm)
-		menucmp = 0;
-
-	    do_single(*mc);
-	    minfo.cur = mc;
-
-	    if (!*++(minfo.cur)) {
-		do {
-		    if (!(minfo.group = (minfo.group)->next))
-			break;
-		} while (!(minfo.group)->mcount);
-		if (!minfo.group)
-		    break;
-		minfo.cur = minfo.group->matches;
-	    }
-	    mc = minfo.cur;
-	}
-	menucmp = 0;
 	minfo.cur = NULL;
 
 	if (forcelist)
@@ -1604,7 +1577,7 @@ addmatches(Cadata dat, char **argv)
     Brinfo bp, bpl = brbeg, obpl, bsl = brend, obsl;
     Heap oldheap;
 
-    if (!*argv) {
+    if (!*argv && !(dat->aflags & CAF_ALL)) {
 	SWITCHHEAPS(oldheap, compheap) {
 	    /* Select the group in which to store the matches. */
 	    gflags = (((dat->aflags & CAF_NOSORT ) ? CGF_NOSORT  : 0) |
@@ -2042,6 +2015,36 @@ addmatches(Cadata dat, char **argv)
 	    set_list_array(dat->dpar, dparl);
 	if (dat->exp)
 	    addexpl();
+	if (!hasallmatch && (dat->aflags & CAF_ALL)) {
+	    Cmatch cm = (Cmatch) zhalloc(sizeof(struct cmatch));
+
+	    memset(cm, 0, sizeof(struct cmatch));
+	    cm->str = dupstring("<all>");
+	    cm->flags = (dat->flags | CMF_ALL |
+			 (complist ?
+			  ((strstr(complist, "packed") ? CMF_PACKED : 0) |
+			   (strstr(complist, "rows")   ? CMF_ROWS   : 0)) : 0));
+	    if (disp) {
+		if (!*++disp)
+		    disp = NULL;
+		if (disp)
+		    cm->disp = dupstring(*disp);
+	    } else {
+		cm->disp = dupstring("");
+		cm->flags |= CMF_DISPLINE;
+	    }
+	    mnum++;
+	    ainfo->count++;
+	    if (curexpl)
+		curexpl->count++;
+
+	    addlinknode(matches, cm);
+
+	    newmatches = 1;
+	    mgroup->new = 1;
+
+	    hasallmatch = 1;
+	}
     } SWITCHBACKHEAPS(oldheap);
 
     /* We switched back to the current heap, now restore the stack of
@@ -2695,7 +2698,7 @@ dupmatch(Cmatch m, int nbeg, int nend)
     r->pre = ztrdup(m->pre);
     r->suf = ztrdup(m->suf);
     r->flags = m->flags;
-    if (nbeg) {
+    if (m->brpl) {
 	int *p, *q, i;
 
 	r->brpl = (int *) zalloc(nbeg * sizeof(int));
@@ -2704,7 +2707,7 @@ dupmatch(Cmatch m, int nbeg, int nend)
 	    *p = *q;
     } else
 	r->brpl = NULL;
-    if (nend) {
+    if (m->brsl) {
 	int *p, *q, i;
 
 	r->brsl = (int *) zalloc(nend * sizeof(int));
@@ -2888,8 +2891,10 @@ freematch(Cmatch m, int nbeg, int nend)
     zsfree(m->remf);
     zsfree(m->disp);
     zsfree(m->autoq);
-    zfree(m->brpl, nbeg * sizeof(int));
-    zfree(m->brsl, nend * sizeof(int));
+    if (m->brpl)
+	zfree(m->brpl, nbeg * sizeof(int));
+    if (m->brsl)
+	zfree(m->brsl, nend * sizeof(int));
 
     zfree(m, sizeof(m));
 }
diff --git a/Src/Zle/complete.c b/Src/Zle/complete.c
index 20da967ef..df9faed7a 100644
--- a/Src/Zle/complete.c
+++ b/Src/Zle/complete.c
@@ -452,6 +452,9 @@ bin_compadd(char *name, char **argv, char *ops, int func)
 	    case 'Q':
 		dat.aflags |= CAF_QUOTE;
 		break;
+	    case 'C':
+		dat.aflags |= CAF_ALL;
+		break;
 	    case 'f':
 		dat.flags |= CMF_FILE;
 		break;
@@ -604,7 +607,7 @@ bin_compadd(char *name, char **argv, char *ops, int func)
  ca_args:
 
     if (!*argv && !dat.group && !dat.mesg &&
-	!(dat.aflags & (CAF_NOSORT|CAF_UNIQALL|CAF_UNIQCON)))
+	!(dat.aflags & (CAF_NOSORT|CAF_UNIQALL|CAF_UNIQCON|CAF_ALL)))
 	return 1;
 
     dat.match = match = cpcmatcher(match);
diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c
index a7dbf6412..2334a2612 100644
--- a/Src/Zle/complist.c
+++ b/Src/Zle/complist.c
@@ -1375,6 +1375,10 @@ clprintm(Cmgroup g, Cmatch *mp, int mc, int ml, int lastc, int width,
 	return 0;
     }
     m = *mp;
+
+    if ((m->flags & CMF_ALL) && (!m->disp || !m->disp[0]))
+	bld_all_str(m);
+
     mlastm = m->gnum;
     if (m->disp && (m->flags & CMF_DISPLINE)) {
 	if (mselect >= 0) {
diff --git a/Src/Zle/compresult.c b/Src/Zle/compresult.c
index 924cf3dcd..cce06d1e3 100644
--- a/Src/Zle/compresult.c
+++ b/Src/Zle/compresult.c
@@ -570,36 +570,40 @@ instmatch(Cmatch m, int *scs)
 mod_export int
 hasbrpsfx(Cmatch m, char *pre, char *suf)
 {
-    char *op = lastprebr, *os = lastpostbr;
-    VARARR(char, oline, ll);
-    int oll = ll, ocs = cs, ole = lastend, opcs = brpcs, oscs = brscs, ret;
+    if (m->flags & CMF_ALL)
+	return 1;
+    else {
+	char *op = lastprebr, *os = lastpostbr;
+	VARARR(char, oline, ll);
+	int oll = ll, ocs = cs, ole = lastend, opcs = brpcs, oscs = brscs, ret;
 
-    memcpy(oline, line, ll);
+	memcpy(oline, line, ll);
 
-    lastprebr = lastpostbr = NULL;
+	lastprebr = lastpostbr = NULL;
 
-    instmatch(m, NULL);
+	instmatch(m, NULL);
 
-    cs = 0;
-    foredel(ll);
-    spaceinline(oll);
-    memcpy(line, oline, oll);
-    cs = ocs;
-    lastend = ole;
-    brpcs = opcs;
-    brscs = oscs;
+	cs = 0;
+	foredel(ll);
+	spaceinline(oll);
+	memcpy(line, oline, oll);
+	cs = ocs;
+	lastend = ole;
+	brpcs = opcs;
+	brscs = oscs;
 
-    ret = (((!pre && !lastprebr) ||
-	    (pre && lastprebr && !strcmp(pre, lastprebr))) &&
-	   ((!suf && !lastpostbr) ||
-	    (suf && lastpostbr && !strcmp(suf, lastpostbr))));
+	ret = (((!pre && !lastprebr) ||
+		(pre && lastprebr && !strcmp(pre, lastprebr))) &&
+	       ((!suf && !lastpostbr) ||
+		(suf && lastpostbr && !strcmp(suf, lastpostbr))));
 
-    zsfree(lastprebr);
-    zsfree(lastpostbr);
-    lastprebr = op;
-    lastpostbr = os;
+	zsfree(lastprebr);
+	zsfree(lastpostbr);
+	lastprebr = op;
+	lastpostbr = os;
 
-    return ret;
+	return ret;
+    }
 }
 
 /* Handle the case were we found more than one match. */
@@ -748,6 +752,65 @@ ztat(char *nam, struct stat *buf, int ls)
     }
 }
 
+/* Insert all matches in the command line. */
+
+/**/
+void
+do_allmatches(int end)
+{
+    int first = 1, nm = nmatches - 1, omc = menucmp, oma = menuacc, e;
+    Cmatch *mc;
+    struct menuinfo mi;
+    char *p = (brbeg ? ztrdup(lastbrbeg->str) : NULL);
+
+    memcpy(&mi, &minfo, sizeof(struct menuinfo));
+    menucmp = 1;
+    menuacc = 0;
+
+    for (minfo.group = amatches;
+	 minfo.group && !(minfo.group)->mcount;
+	 minfo.group = (minfo.group)->next);
+
+    mc = (minfo.group)->matches;
+
+    while (1) {
+	if (!((*mc)->flags & CMF_ALL)) {
+	    if (!first)
+		accept_last();
+	    first = 0;
+
+	    if (!omc && !--nm)
+		menucmp = 0;
+
+	    do_single(*mc);
+	}
+	minfo.cur = mc;
+
+	if (!*++(minfo.cur)) {
+	    do {
+		if (!(minfo.group = (minfo.group)->next))
+		    break;
+	    } while (!(minfo.group)->mcount);
+	    if (!minfo.group)
+		break;
+	    minfo.cur = minfo.group->matches;
+	}
+	mc = minfo.cur;
+    }
+    menucmp = omc;
+    menuacc = oma;
+
+    e = minfo.end;
+    memcpy(&minfo, &mi, sizeof(struct menuinfo));
+    minfo.end = e;
+    minfo.len = e - minfo.pos;
+
+    if (p) {
+	zsfree(lastbrbeg->str);
+	lastbrbeg->str = p;
+    }
+}
+
 /* Insert a single match in the command line. */
 
 /**/
@@ -785,6 +848,10 @@ do_single(Cmatch m)
     cs = minfo.pos;
     foredel(l);
 
+    if (m->flags & CMF_ALL)
+	do_allmatches(0);
+    else {
+
     /* And then we insert the new string. */
     minfo.len = instmatch(m, &scs);
     minfo.end = cs;
@@ -956,6 +1023,7 @@ do_single(Cmatch m)
 	runhookdef(INSERTMATCHHOOK, (void *) &dat);
 	minfo.cur = om;
     }
+    }
 }
 
 /* Do completion, given that we are in the middle of a menu completion.  We *
@@ -1886,6 +1954,54 @@ printlist(int over, CLPrintFunc printm, int showall)
 }
 
 /**/
+mod_export void
+bld_all_str(Cmatch all)
+{
+    Cmgroup g;
+    Cmatch *mp, m;
+    int len = columns - 5, t, add = 0;
+    VARARR(char, buf, columns + 1);
+
+    buf[0] = '\0';
+
+    for (g = amatches; g && !g->mcount; g = g->next);
+
+    mp = g->matches;
+    while (1) {
+	m = *mp;
+	if (!(m->flags & (CMF_ALL | CMF_HIDE)) && m->str) {
+	    t = strlen(m->str) + add;
+	    if (len >= t) {
+		if (add)
+		    strcat(buf, " ");
+		strcat(buf, m->str);
+		len -= t;
+		add = 1;
+	    } else {
+		if (len > add + 2) {
+		    if (add)
+			strcat(buf, " ");
+		    strncat(buf, m->str, len);
+		}
+		strcat(buf, " ...");
+		break;
+	    }
+	}
+	if (!*++mp) {
+	    do {
+		if (!(g = g->next))
+		    break;
+	    } while (!g->mcount);
+	    if (!g)
+		break;
+	    mp = g->matches;
+	}
+    }
+    zsfree(all->disp);
+    all->disp = ztrdup(buf);
+}
+
+/**/
 static void
 iprintm(Cmgroup g, Cmatch *mp, int mc, int ml, int lastc, int width,
 	char *path, struct stat *buf)
@@ -1897,6 +2013,8 @@ iprintm(Cmgroup g, Cmatch *mp, int mc, int ml, int lastc, int width,
 	return;
 
     m = *mp;
+    if ((m->flags & CMF_ALL) && (!m->disp || !m->disp[0]))
+	bld_all_str(m);
     if (m->disp) {
 	if (m->flags & CMF_DISPLINE) {
 	    printfmt(m->disp, 0, 1, 0);