From eba59194d72250402bdbb97a866ffea89ec9d7a7 Mon Sep 17 00:00:00 2001 From: Sven Wischnowsky Date: Wed, 25 Jul 2001 08:52:34 +0000 Subject: make display for groups in _describe nicer; improve packing with list_packed; leave space for type character (list_types) only in groups with at least one file name (15477) --- ChangeLog | 9 + Completion/Base/Utility/_describe | 40 ++-- Doc/Zsh/compwid.yo | 12 + Src/Zle/comp.h | 3 + Src/Zle/compcore.c | 69 +++--- Src/Zle/complete.c | 18 ++ Src/Zle/complist.c | 7 +- Src/Zle/compresult.c | 50 ++++- Src/Zle/computil.c | 456 ++++++++++++++++++++++++++++++-------- 9 files changed, 506 insertions(+), 158 deletions(-) diff --git a/ChangeLog b/ChangeLog index b3c2e034c..3697bc10e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2001-07-25 Sven Wischnowsky + + * 15477: Completion/Base/Utility/_describe, Doc/Zsh/compwid.yo, + Src/Zle/comp.h, Src/Zle/compcore.c, Src/Zle/complete.c, + Src/Zle/complist.c, Src/Zle/compresult.c, Src/Zle/computil.c: + make display for groups in _describe nicer; improve packing + with list_packed; leave space for type character (list_types) + only in groups with at least one file name + 2001-07-24 Sven Wischnowsky * 15470: Src/parse.c: remove nulargs in here strings diff --git a/Completion/Base/Utility/_describe b/Completion/Base/Utility/_describe index 45b8c17d6..2783c25d1 100644 --- a/Completion/Base/Utility/_describe +++ b/Completion/Base/Utility/_describe @@ -2,8 +2,9 @@ # This can be used to add options or values with descriptions as matches. -local _opt _expl _tmps _tmpd _tmph _tmpmd _tmpms _tmpmh -local _type=values _descr _ret=1 _showd _nm _hide _args _grp +local _opt _expl _tmpm _tmpd +local _type=values _descr _ret=1 _showd _nm _hide _args _grp _sep +local csl="$compstate[list]" csl2 # Get the option. @@ -27,6 +28,7 @@ if zstyle -T ":completion:${curcontext}:$_type" list-grouped; then _argv=( "$@" ) _grp=(-g) + _sep='-- ' _new=( "$1" ) shift @@ -66,43 +68,33 @@ if zstyle -T ":completion:${curcontext}:$_type" list-grouped; then set - "$_argv[@]" else _grp=() + _sep=' -- ' fi _descr="$1" shift [[ "$_type" = options ]] && - zstyle -t ":completion:${curcontext}:options" prefix-hidden && _hide=yes + zstyle -t ":completion:${curcontext}:options" prefix-hidden && + _hide="${(M)PREFIX##(--|[-+])}" _tags "$_type" while _tags; do while _next_label "$_type" _expl "$_descr"; do if [[ -n "$_showd" ]]; then - compdescribe -I ' -- ' "$_grp[@]" "$@" + compdescribe -I "$_hide" "$_sep" _expl "$_grp[@]" "$@" else - compdescribe -i "$@" + compdescribe -i "$_hide" "$@" fi - while compdescribe -g _args _tmpd _tmpmd _tmph _tmpmh _tmps _tmpms; do - - # See if we should remove the option prefix characters. - - if [[ -n "$_hide" ]]; then - if [[ "$PREFIX" = --* ]]; then - _tmpd=( "${(@)_tmpd#--}" ) - _tmph=( "${(@)_tmph#--}" ) - _tmps=( "${(@)_tmps#--}" ) - elif [[ "$PREFIX" = [-+]* ]]; then - _tmpd=( "${(@)_tmpd#[-+]}" ) - _tmph=( "${(@)_tmph#[-+]}" ) - _tmps=( "${(@)_tmps#[-+]}" ) - fi - fi - - compadd "$_args[@]" "$_expl[@]" -ld _tmpd -a _tmpmd && _ret=0 - compadd -n "$_args[@]" "$_expl[@]" -ld _tmph -a _tmpmh && _ret=0 - compadd "$_args[@]" "$_expl[@]" -d _tmps -a _tmpms && _ret=0 + compstate[list]="$csl" + + while compdescribe -g csl2 _args _tmpm _tmpd; do + + compstate[list]="$csl $csl2" + + compadd "$_args[@]" -d _tmpd -a _tmpm && _ret=0 done done (( _ret )) || return 0 diff --git a/Doc/Zsh/compwid.yo b/Doc/Zsh/compwid.yo index 8b3537100..e3f43e382 100644 --- a/Doc/Zsh/compwid.yo +++ b/Doc/Zsh/compwid.yo @@ -441,6 +441,7 @@ xitem([ tt(-W) var(file-prefix) ] [ tt(-d) var(array) ]) xitem([ tt(-J) var(name) ] [ tt(-V) var(name) ] [ tt(-X) var(explanation) ] [ tt(-x) var(message) ]) xitem([ tt(-r) var(remove-chars) ] [ tt(-R) var(remove-func) ]) xitem([ tt(-D) var(array) ] [ tt(-O) var(array) ] [ tt(-A) var(array) ]) +xitem([ tt(-E) var(number) ]) item([ tt(-M) var(match-spec) ] [ tt(--) ] [ var(words) ... ])( This builtin command can be used to add matches directly and control @@ -664,6 +665,17 @@ 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. ) +item(tt(-E))( +This option adds var(number) empty matches after the var(words) have +been added. An empty match takes up space in completion listings but +will never be inserted in the line and can't be selected with menu +completion or menu selection. This makes empty matches only useful to +format completion lists and to make explanatory string be shown in +completion lists (since empty matches can be given display strings +with the tt(-d) option). And because all but one empty string would +otherwise be removed, this option implies the tt(-V) and tt(-1) +options (even if an explicit tt(-J) option is given). +) 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 22029d511..c06e7aa7e 100644 --- a/Src/Zle/comp.h +++ b/Src/Zle/comp.h @@ -85,6 +85,7 @@ struct cmgroup { #define CGF_UNIQCON 16 /* remove consecutive duplicates */ #define CGF_PACKED 32 /* LIST_PACKED for this group */ #define CGF_ROWS 64 /* LIST_ROWS_FIRST for this group */ +#define CGF_FILES 128 /* contains file names */ /* This is the struct used to hold matches. */ @@ -125,6 +126,7 @@ struct cmatch { #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 */ +#define CMF_DUMMY (1<<14) /* unselectable dummy match */ /* Stuff for completion matcher control. */ @@ -264,6 +266,7 @@ struct cadata { char *dpar; /* array to delete non-matches in (-D) */ char *disp; /* array with display lists (-d) */ char *mesg; /* message to show unconditionally (-x) */ + int dummies; /* add that many dummy matches */ }; /* List data. */ diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c index 97ed6d58f..00dfea935 100644 --- a/Src/Zle/compcore.c +++ b/Src/Zle/compcore.c @@ -1558,6 +1558,40 @@ get_data_arr(char *name, int keys) return ret; } +static void +addmatch(char *str, int flags, char ***dispp, int line) +{ + Cmatch cm = (Cmatch) zhalloc(sizeof(struct cmatch)); + char **disp = *dispp; + + memset(cm, 0, sizeof(struct cmatch)); + cm->str = dupstring(str); + cm->flags = (flags | + (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 if (line) { + cm->disp = dupstring(""); + cm->flags |= CMF_DISPLINE; + } + mnum++; + ainfo->count++; + if (curexpl) + curexpl->count++; + + addlinknode(matches, cm); + + newmatches = 1; + mgroup->new = 1; + + *dispp = disp; +} + /* 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. */ @@ -1583,7 +1617,7 @@ addmatches(Cadata dat, char **argv) Brinfo bp, bpl = brbeg, obpl, bsl = brend, obsl; Heap oldheap; - if (!*argv && !(dat->aflags & CAF_ALL)) { + if (!*argv && !dat->dummies && !(dat->aflags & CAF_ALL)) { SWITCHHEAPS(oldheap, compheap) { /* Select the group in which to store the matches. */ gflags = (((dat->aflags & CAF_NOSORT ) ? CGF_NOSORT : 0) | @@ -1602,6 +1636,8 @@ addmatches(Cadata dat, char **argv) return 1; } + if (dat->dummies) + dat->aflags = dat->aflags | CAF_NOSORT | CAF_UNIQALL; for (bp = brbeg; bp; bp = bp->next) bp->curpos = ((dat->aflags & CAF_QUOTE) ? bp->pos : bp->qpos); for (bp = brend; bp; bp = bp->next) @@ -2022,35 +2058,12 @@ addmatches(Cadata dat, char **argv) 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(""); - 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; - + addmatch("", dat->flags | CMF_ALL, &disp, 1); hasallmatch = 1; } + while (dat->dummies--) + addmatch("", dat->flags | CMF_DUMMY, &disp, 0); + } SWITCHBACKHEAPS(oldheap); /* We switched back to the current heap, now restore the stack of diff --git a/Src/Zle/complete.c b/Src/Zle/complete.c index 574e638ac..106e0ddab 100644 --- a/Src/Zle/complete.c +++ b/Src/Zle/complete.c @@ -435,6 +435,7 @@ bin_compadd(char *name, char **argv, char *ops, int func) dat.match = NULL; dat.flags = 0; dat.aflags = CAF_MATCH; + dat.dummies = 0; for (; *argv && **argv == '-'; argv++) { if (!(*argv)[1]) { @@ -565,6 +566,23 @@ bin_compadd(char *name, char **argv, char *ops, int func) case 'l': dat.flags |= CMF_DISPLINE; break; + case 'E': + if (p[1]) { + dat.dummies = atoi(p + 1); + p = "" - 1; + } else if (argv[1]) { + argv++; + dat.dummies = atoi(*argv); + p = "" - 1; + } else { + zwarnnam(name, "number expected after -%c", NULL, *p); + return 1; + } + if (dat.dummies < 0) { + zwarnnam(name, "invalid number: %d", NULL, dat.dummies); + return 1; + } + break; case '-': argv++; goto ca_args; diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c index 94fd2cc56..14cb16d4c 100644 --- a/Src/Zle/complist.c +++ b/Src/Zle/complist.c @@ -1394,7 +1394,7 @@ clprintm(Cmgroup g, Cmatch *mp, int mc, int ml, int lastc, int width, mlastm = m->gnum; if (m->disp && (m->flags & CMF_DISPLINE)) { - if (mselect >= 0) { + if (mselect >= 0 && !(m->flags & CMF_DUMMY)) { int mm = (mcols * ml), i; for (i = mcols; i--; ) { @@ -1441,7 +1441,7 @@ clprintm(Cmgroup g, Cmatch *mp, int mc, int ml, int lastc, int width, } else mx = mc * g->width; - if (mselect >= 0) { + if (mselect >= 0 && !(m->flags & CMF_DUMMY)) { int mm = mcols * ml, i; for (i = (width ? width : mcols); i--; ) { @@ -1482,7 +1482,7 @@ clprintm(Cmgroup g, Cmatch *mp, int mc, int ml, int lastc, int width, len = niceztrlen(m->disp ? m->disp : m->str); mlprinted = len / columns; - if (isset(LISTTYPES) && buf) { + if ((g->flags & CGF_FILES) && buf) { if (m->gnum != mselect) { zcoff(); zcputs(&mcolors, g->name, COL_TC); @@ -1684,6 +1684,7 @@ domenuselect(Hookdef dummy, Chdata dat) noselect = 1; while ((menuacc && !hasbrpsfx(*(minfo.cur), minfo.prebr, minfo.postbr)) || + ((*minfo.cur)->flags & CMF_DUMMY) || (((*minfo.cur)->flags & (CMF_NOLIST | CMF_MULT)) && (!(*minfo.cur)->str || !*(*minfo.cur)->str))) do_menucmp(0); diff --git a/Src/Zle/compresult.c b/Src/Zle/compresult.c index 0e7bbedba..6b5d7df38 100644 --- a/Src/Zle/compresult.c +++ b/Src/Zle/compresult.c @@ -1160,6 +1160,7 @@ do_menucmp(int lst) } } while ((menuacc && !hasbrpsfx(*(minfo.cur), minfo.prebr, minfo.postbr)) || + ((*minfo.cur)->flags & CMF_DUMMY) || (((*minfo.cur)->flags & (CMF_NOLIST | CMF_MULT)) && (!(*minfo.cur)->str || !*(*minfo.cur)->str))); /* ... and insert it into the command line. */ @@ -1183,6 +1184,7 @@ reverse_menu(Hookdef dummy, void *dummy2) minfo.cur--; } while ((menuacc && !hasbrpsfx(*(minfo.cur), minfo.prebr, minfo.postbr)) || + ((*minfo.cur)->flags & CMF_DUMMY) || (((*minfo.cur)->flags & (CMF_NOLIST | CMF_MULT)) && (!(*minfo.cur)->str || !*(*minfo.cur)->str))); metafy_line(); @@ -1378,7 +1380,7 @@ calclist(int showall) Cmgroup g; Cmatch *p, m; Cexpl *e; - int hidden = 0, nlist = 0, nlines = 0, add = 2 + isset(LISTTYPES); + int hidden = 0, nlist = 0, nlines = 0, add; int max = 0, i; VARARR(int, mlens, nmatches + 1); @@ -1392,6 +1394,7 @@ calclist(int showall) for (g = amatches; g; g = g->next) { char **pp = g->ylist; int nl = 0, l, glong = 1, gshort = columns, ndisp = 0, totl = 0; + int hasf = 0; g->flags |= CGF_PACKED | CGF_ROWS; @@ -1437,6 +1440,8 @@ calclist(int showall) } } else if (!onlyexpl) { for (p = g->matches; (m = *p); p++) { + if (m->flags & CMF_FILE) + hasf = 1; if (menuacc && !hasbrpsfx(m, minfo.prebr, minfo.postbr)) { m->flags |= CMF_HIDE; continue; @@ -1496,6 +1501,11 @@ calclist(int showall) e++; } } + if (isset(LISTTYPES) && hasf) { + g->flags |= CGF_FILES; + add = 3; + } else + add = 2; g->totl = totl + (ndisp * add); g->dcount = ndisp; g->width = glong + add; @@ -1513,6 +1523,7 @@ calclist(int showall) int *ws, tlines, tline, tcols, maxlen, nth, width, glines; for (g = amatches; g; g = g->next) { + add = 2 + !!(g->flags & CGF_FILES); glines = 0; zfree(g->widths, 0); @@ -1523,7 +1534,8 @@ calclist(int showall) 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; + g->width += ((max - (g->width * g->cols - add)) / + g->cols); } else { g->cols = 1; g->width = 1; @@ -1559,6 +1571,8 @@ calclist(int showall) if (!(g->flags & CGF_PACKED)) continue; + add = 2 + !!(g->flags & CGF_FILES); + ws = g->widths = (int *) zalloc(columns * sizeof(int)); memset(ws, 0, columns * sizeof(int)); tlines = g->lins; @@ -1666,7 +1680,7 @@ calclist(int showall) } else if (g->width) { if (g->flags & CGF_ROWS) { int addlen, count, tcol, maxlines = 0, llines, i; - int beg = columns / g->shortest, end = g->cols; + int beg = columns / g->shortest, end = g->cols, fe = 1; Cmatch *first; while (1) { @@ -1677,7 +1691,8 @@ calclist(int showall) count = g->dcount; count > 0; count--) { m = *p; - addlen = mlens[m->gnum] + add; + addlen = (mlens[m->gnum] + + (tcol == tcols - 1 ? 0 : add)); if (addlen > maxlen) maxlen = addlen; for (i = tcols; i && *p; i--) @@ -1706,15 +1721,21 @@ calclist(int showall) break; if (beg == end) { - beg--; - end--; + if (fe) { + beg += 2; + end += 2; + fe = 0; + } else { + beg--; + end--; + } } else if (width < columns) { if ((end = tcols) == beg - 1) end++; } else { if ((beg = tcols) - 1 == end) end++; - } + } } if (tcols > g->cols) tlines = maxlines; @@ -1723,7 +1744,7 @@ calclist(int showall) int smask = ((showall ? 0 : (CMF_NOLIST | CMF_MULT)) | CMF_HIDE); int beg = ((g->totl + columns) / columns); - int end = g->lins; + int end = g->lins, fe = 1; while (1) { tlines = (beg + end) >> 1; @@ -1755,8 +1776,14 @@ calclist(int showall) break; if (beg == end) { - beg++; - end++; + if (fe) { + beg -= 2; + end -= 2; + fe = 0; + } else { + beg++; + end++; + } } else if (width < columns) { if ((end = tlines) == beg + 1) end--; @@ -1783,6 +1810,7 @@ calclist(int showall) } } for (g = amatches; g; g = g->next) { + add = 2 + !!(g->flags & CGF_FILES); if (g->widths) { int *p, a = (max - g->totl + add) / g->cols; @@ -2152,7 +2180,7 @@ iprintm(Cmgroup g, Cmatch *mp, int mc, int ml, int lastc, int width, nicezputs(m->str, shout); len = niceztrlen(m->str); - if (isset(LISTTYPES) && buf) { + if ((g->flags & CGF_FILES) && buf) { putc(file_type(buf->st_mode), shout); len++; } diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c index 5c4fc3ed5..7548a87bf 100644 --- a/Src/Zle/computil.c +++ b/Src/Zle/computil.c @@ -35,6 +35,7 @@ typedef struct cdset *Cdset; typedef struct cdstr *Cdstr; +typedef struct cdrun *Cdrun; struct cdstate { int showd; /* != 0 if descriptions should be shown */ @@ -43,6 +44,11 @@ struct cdstate { Cdset sets; /* the sets of matches */ int pre; /* longest prefix (before description) */ int suf; /* longest suffix (description) */ + int maxg; /* size of largest group */ + int groups; /* number of groups */ + int descs; /* number of non-group matches with desc */ + int gpre; /* prefix length for group display */ + Cdrun runs; /* runs to report to shell code */ }; struct cdstr { @@ -50,10 +56,25 @@ struct cdstr { char *str; /* the string to display */ char *desc; /* the description or NULL */ char *match; /* the match to add */ + int len; /* length of str or match */ Cdstr other; /* next string with the same description */ int kind; /* 0: not in a group, 1: the first, 2: other */ + Cdset set; /* the set this string is in */ + Cdstr run; /* next in this run */ }; +struct cdrun { + Cdrun next; /* ... */ + int type; /* see CRT_* below */ + Cdstr strs; /* strings in this run */ + int count; /* number of strings in this run */ +}; + +#define CRT_SIMPLE 0 +#define CRT_DESC 1 +#define CRT_SPEC 2 +#define CRT_DUMMY 3 + struct cdset { Cdset next; /* guess what */ char **opts; /* the compadd-options */ @@ -62,11 +83,6 @@ struct cdset { int desc; /* number of matches with description */ }; -/* Maximum string length when used with descriptions. */ - -#define CD_MAXLEN 30 - - static struct cdstate cd_state; static int cd_parsed = 0; @@ -75,6 +91,7 @@ freecdsets(Cdset p) { Cdset n; Cdstr s, sn; + Cdrun r, rn; for (; p; p = n) { n = p->next; @@ -88,6 +105,10 @@ freecdsets(Cdset p) zsfree(s->match); zfree(s, sizeof(*s)); } + for (r = cd_state.runs; r; r = rn) { + rn = r->next; + zfree(r, sizeof(*r)); + } zfree(p, sizeof(*p)); } } @@ -99,14 +120,14 @@ cd_group() { Cdset set1, set2; Cdstr str1, str2, *strp; - int yep = 0; - char *buf; + int num; for (set1 = cd_state.sets; set1; set1 = set1->next) { for (str1 = set1->strs; str1; str1 = str1->next) { if (!str1->desc || str1->kind != 0) continue; + num = 1; strp = &(str1->other); for (set2 = set1; set2; set2 = set2->next) @@ -115,33 +136,18 @@ cd_group() if (str2->desc && !strcmp(str1->desc, str2->desc)) { str1->kind = 1; str2->kind = 2; - zsfree(str2->desc); - str2->desc = ztrdup("|"); + num++; *strp = str2; strp = &(str2->other); - yep = 1; } *strp = NULL; - } - } - if (!yep) - return; - - for (set1 = cd_state.sets; set1; set1 = set1->next) { - for (str1 = set1->strs; str1; str1 = str1->next) { - if (str1->kind != 1) - continue; - - buf = str1->str; - for (str2 = str1->other; str2; str2 = str2->other) - buf = zhtricat(buf, ", ", str2->str); + if (num > 1) + cd_state.groups++; + else + cd_state.descs++; - for (str2 = str1; str2; str2 = str2->other) { - if (str2->str == str2->match) - str2->match = ztrdup(str2->match); - zsfree(str2->str); - str2->str = ztrdup(buf); - } + if (num > cd_state.maxg) + cd_state.maxg = num; } } } @@ -171,14 +177,172 @@ cd_calc() } } } - if (cd_state.pre > CD_MAXLEN) - cd_state.pre = CD_MAXLEN; +} + +static int +cd_sort(const void *a, const void *b) +{ + return strcmp((*((Cdstr *) a))->str, (*((Cdstr *) b))->str); +} + +static void +cd_prep() +{ + Cdrun run, *runp; + Cdset set; + Cdstr str, *strp; + + runp = &(cd_state.runs); + + if (cd_state.groups) { + int lines = cd_state.groups + cd_state.descs; + VARARR(Cdstr, grps, lines); + VARARR(int, wids, cd_state.maxg); + Cdstr gs, gp, gn, *gpp; + int i, j; + + memset(wids, 0, cd_state.maxg * sizeof(int)); + strp = grps; + + for (set = cd_state.sets; set; set = set->next) + for (str = set->strs; str; str = str->next) { + if (str->kind != 1) { + if (!str->kind && str->desc) { + str->other = NULL; + *strp++ = str; + } + continue; + } + gs = str; + gs->kind = 2; + gp = str->other; + gs->other = NULL; + for (; gp; gp = gn) { + gn = gp->other; + gp->other = NULL; + for (gpp = &gs; *gpp && (*gpp)->len > gp->len; + gpp = &((*gpp)->other)); + gp->other = *gpp; + *gpp = gp; + } + for (gp = gs, i = 0; gp; gp = gp->other, i++) + if (gp->len > wids[i]) + wids[i] = gp->len; + + *strp++ = gs; + } + + qsort(grps, lines, sizeof(Cdstr), cd_sort); + + for (i = lines, strp = grps; i; i--, strp++) { + for (j = 0, gs = *strp; gs->other; gs = gs->other, j++) { + *runp = run = (Cdrun) zalloc(sizeof(*run)); + runp = &(run->next); + run->type = CRT_SPEC; + run->strs = gs; + gs->run = NULL; + run->count = 1; + } + *runp = run = (Cdrun) zalloc(sizeof(*run)); + runp = &(run->next); + run->type = CRT_DUMMY + cd_state.maxg - j - 1; + run->strs = gs; + gs->run = NULL; + run->count = 1; + } + for (set = cd_state.sets; set; set = set->next) { + for (i = 0, gs = NULL, gpp = &gs, str = set->strs; + str; str = str->next) { + if (str->kind || str->desc) + continue; + + i++; + *gpp = str; + gpp = &(str->run); + } + *gpp = NULL; + if (i) { + *runp = run = (Cdrun) zalloc(sizeof(*run)); + runp = &(run->next); + run->type = CRT_SIMPLE; + run->strs = gs; + run->count = i; + } + } + cd_state.gpre = 0; + for (i = 0; i < cd_state.maxg; i++) + cd_state.gpre += wids[i] + 2; + } else if (cd_state.showd) { + for (set = cd_state.sets; set; set = set->next) { + if (set->desc) { + *runp = run = (Cdrun) zalloc(sizeof(*run)); + runp = &(run->next); + run->type = CRT_DESC; + strp = &(run->strs); + for (str = set->strs; str; str = str->next) + if (str->desc) { + *strp = str; + strp = &(str->run); + } + *strp = NULL; + run->count = set->desc; + } + if (set->desc != set->count) { + *runp = run = (Cdrun) zalloc(sizeof(*run)); + runp = &(run->next); + run->type = CRT_SIMPLE; + strp = &(run->strs); + for (str = set->strs; str; str = str->next) + if (!str->desc) { + *strp = str; + strp = &(str->run); + } + *strp = NULL; + run->count = set->count - set->desc; + } + } + } else { + for (set = cd_state.sets; set; set = set->next) + if (set->count) { + *runp = run = (Cdrun) zalloc(sizeof(*run)); + runp = &(run->next); + run->type = CRT_SIMPLE; + run->strs = set->strs; + for (str = set->strs; str; str = str->next) + str->run = str->next; + run->count = set->count; + } + } + *runp = NULL; +} + +/* Duplicate and concatenate two arrays. Return the result. */ + +static char ** +cd_arrcat(char **a, char **b) +{ + if (!b) + return zarrdup(a); + else { + char **r = (char **) zalloc((arrlen(a) + arrlen(b) + 1) * + sizeof(char *)); + char **p = r; + + for (; *a; a++) + *p++ = ztrdup(*a); + for (; *b; b++) + *p++ = ztrdup(*b); + + *p = NULL; + + return r; + } } /* Initialisation. Store and calculate the string and matches and so on. */ static int -cd_init(char *nam, char *sep, char **args, int disp) +cd_init(char *nam, char *hide, char *sep, char **opts, char **args, int disp) { Cdset *setp, set; Cdstr *strp, str; @@ -195,6 +359,7 @@ cd_init(char *nam, char *sep, char **args, int disp) cd_state.slen = ztrlen(sep); cd_state.sets = NULL; cd_state.showd = disp; + cd_state.maxg = cd_state.groups = cd_state.descs = 0; if (*args && !strcmp(*args, "-g")) { args++; @@ -219,6 +384,7 @@ cd_init(char *nam, char *sep, char **args, int disp) str->kind = 0; str->other = NULL; + str->set = set; for (tmp = *ap; *tmp && *tmp != ':'; tmp++) if (*tmp == '\\' && tmp[1]) @@ -230,6 +396,7 @@ cd_init(char *nam, char *sep, char **args, int disp) str->desc = NULL; *tmp = '\0'; str->str = str->match = ztrdup(rembslash(*ap)); + str->len = strlen(str->str); } if (str) str->next = NULL; @@ -246,13 +413,23 @@ cd_init(char *nam, char *sep, char **args, int disp) args++; } + if (hide && *hide) { + for (str = set->strs; str; str = str->next) { + if (str->str == str->match) + str->str = ztrdup(str->str); + if (hide[1] && str->str[0] == '-' && str->str[1] == '-') + strcpy(str->str, str->str + 2); + else if (str->str[0] == '-' || str->str[0] == '+') + strcpy(str->str, str->str + 1); + } + } for (ap = args; *args && (args[0][0] != '-' || args[0][1] != '-' || args[0][2]); args++); tmp = *args; *args = NULL; - set->opts = zarrdup(ap); + set->opts = cd_arrcat(ap, opts); if ((*args = tmp)) args++; } @@ -260,79 +437,157 @@ cd_init(char *nam, char *sep, char **args, int disp) cd_group(); cd_calc(); + cd_prep(); cd_parsed = 1; return 0; } +/* Copy an array with one element in reserve (at the beginning). */ + +static char ** +cd_arrdup(char **a) +{ + char **r = (char **) zalloc((arrlen(a) + 2) * sizeof(char *)); + char **p = r + 1; + + while (*a) + *p++ = ztrdup(*a++); + *p = NULL; + + return r; +} + /* Get the next set. */ static int cd_get(char **params) { - Cdset set; + Cdrun run; - if ((set = cd_state.sets)) { - char **sd, **sdp, **md, **mdp, **sh, **shp, **mh, **mhp; - char **ss, **ssp, **ms, **msp; + if ((run = cd_state.runs)) { Cdstr str; - VARARR(char, buf, cd_state.pre + cd_state.suf + cd_state.slen + 1); - char *sufp = NULL, *disp; + char **mats, **mp, **dpys, **dp, **opts, *csl = ""; - if (cd_state.showd) { - memcpy(buf + cd_state.pre, cd_state.sep, cd_state.slen); - sufp = buf + cd_state.pre + cd_state.slen; - } - sd = (char **) zalloc((set->desc + 1) * sizeof(char *)); - md = (char **) zalloc((set->desc + 1) * sizeof(char *)); - sh = (char **) zalloc((set->desc + 1) * sizeof(char *)); - mh = (char **) zalloc((set->desc + 1) * sizeof(char *)); - ss = (char **) zalloc((set->count + 1) * sizeof(char *)); - ms = (char **) zalloc((set->count + 1) * sizeof(char *)); - - for (sdp = sd, mdp = md, shp = sh, mhp = mh, - ssp = ss, msp = ms, str = set->strs; - str; - str = str->next) { - if (cd_state.showd && str->desc) { - if (strlen(str->str) > CD_MAXLEN) - disp = tricat(str->str, cd_state.sep, str->desc); - else { - strcpy(sufp, str->desc); - memset(buf, ' ', cd_state.pre); - memcpy(buf, str->str, strlen(str->str)); - disp = ztrdup(buf); + cd_state.runs = run->next; + + switch (run->type) { + case CRT_SIMPLE: + mats = mp = (char **) zalloc((run->count + 1) * sizeof(char *)); + dpys = dp = (char **) zalloc((run->count + 1) * sizeof(char *)); + + for (str = run->strs; str; str = str->run) { + *mp++ = ztrdup(str->match); + *dp++ = ztrdup(str->str ? str->str : str->match); + } + *mp = *dp = NULL; + opts = zarrdup(run->strs->set->opts); + if (cd_state.groups) { + /* We are building a columnised list with dummy matches + * but there are also matches without descriptions. + * Those end up in a different group, so make sure that + * groupd doesn't have an explanation. */ + + for (mp = dp = opts; *mp; mp++) { + if (dp[0][0] == '-' && dp[0][1] == 'X') { + if (!dp[0][2] && dp[1]) + mp++; + } else + *dp++ = *mp; } - if (strlen(disp) >= columns) - disp[columns - 1] = '\0'; + *dp = NULL; + } + break; - if (str->kind == 2) { - *shp++ = disp; - *mhp++ = ztrdup(str->match); - } else { - *sdp++ = disp; - *mdp++ = ztrdup(str->match); + case CRT_DESC: + { + VARARR(char, buf, + cd_state.pre + cd_state.suf + cd_state.slen + 1); + char *sufp = NULL; + + memcpy(buf + cd_state.pre, cd_state.sep, cd_state.slen); + sufp = buf + cd_state.pre + cd_state.slen; + + mats = mp = (char **) zalloc((run->count + 1) * sizeof(char *)); + dpys = dp = (char **) zalloc((run->count + 1) * sizeof(char *)); + + for (str = run->strs; str; str = str->run) { + *mp++ = ztrdup(str->match); + memset(buf, ' ', cd_state.pre); + memcpy(buf, str->str, str->len); + strcpy(sufp, str->desc); + if (strlen(buf) >= columns) + buf[columns] = '\0'; + *dp++ = ztrdup(buf); } - } else { - *ssp++ = ztrdup(str->str); - *msp++ = ztrdup(str->match); + *mp = *dp = NULL; + opts = cd_arrdup(run->strs->set->opts); + opts[0] = ztrdup("-l"); + break; + } + case CRT_SPEC: + mats = (char **) zalloc(2 * sizeof(char *)); + dpys = (char **) zalloc(2 * sizeof(char *)); + mats[0] = ztrdup(run->strs->match); + dpys[0] = ztrdup(run->strs->str); + mats[1] = dpys[1] = NULL; + opts = cd_arrdup(run->strs->set->opts); + for (dp = opts + 1; *dp; dp++) + if (dp[0][0] == '-' && dp[0][1] == 'J') + break; + if (*dp) { + char *s = tricat("-1V", "", dp[0] + 2); + + zsfree(*dp); + *dp = s; + + memmove(opts, opts + 1, + (arrlen(opts + 1) + 1) * sizeof(char *)); + + } else + opts[0] = ztrdup("-1V-default-"); + csl = "packed rows"; + break; + + default: + { + int dlen = columns - cd_state.gpre - cd_state.slen; + VARARR(char, dbuf, dlen + cd_state.slen); + char buf[20]; + int i = run->type - CRT_DUMMY; + + sprintf(buf, "-E%d", i + 1); + + mats = (char **) zalloc(2 * sizeof(char *)); + dpys = (char **) zalloc((3 + i) * sizeof(char *)); + mats[0] = ztrdup(run->strs->match); + dpys[0] = ztrdup(run->strs->str); + for (dp = dpys + 1; i; i--, dp++) + *dp = ztrdup(""); + memset(dbuf + cd_state.slen, ' ', dlen - 1); + dbuf[dlen + cd_state.slen - 1] = '\0'; + strcpy(dbuf, cd_state.sep); + memcpy(dbuf + cd_state.slen, + run->strs->desc, + (strlen(run->strs->desc) >= dlen ? dlen - 1 : + strlen(run->strs->desc))); + *dp++ = ztrdup(dbuf); + mats[1] = *dp = NULL; + + opts = cd_arrdup(run->strs->set->opts); + opts[0] = ztrdup(buf); + + csl = "packed rows"; } } - *sdp = *mdp = *shp = *mhp = *ssp = *msp = NULL; - - setaparam(params[0], zarrdup(set->opts)); - setaparam(params[1], sd); - setaparam(params[2], md); - setaparam(params[3], sh); - setaparam(params[4], mh); - setaparam(params[5], ss); - setaparam(params[6], ms); + setsparam(params[0], ztrdup(csl)); + setaparam(params[1], opts); + setaparam(params[2], mats); + setaparam(params[3], dpys); - cd_state.sets = set->next; - set->next = NULL; - freecdsets(set); + zfree(run, sizeof(*run)); - return 0; + return 0; } return 1; } @@ -341,6 +596,8 @@ cd_get(char **params) static int bin_compdescribe(char *nam, char **args, char *ops, int func) { + int n = arrlen(args); + if (incompfunc != 1) { zwarnnam(nam, "can only be called from completion function", NULL, 0); return 1; @@ -351,15 +608,30 @@ bin_compdescribe(char *nam, char **args, char *ops, int func) } switch (args[0][1]) { case 'i': - return cd_init(nam, "", args + 1, 0); + if (n < 2) { + zwarnnam(nam, "not enough arguments", NULL, 0); + + return 1; + } + return cd_init(nam, args[1], "", NULL, args + 2, 0); case 'I': - return cd_init(nam, args[1], args + 2, 1); + if (n < 5) { + zwarnnam(nam, "not enough arguments", NULL, 0); + + return 1; + } else { + char **opts; + + if (!(opts = getaparam(args[3]))) { + zwarnnam(nam, "unknown parameter: %s", args[2], 0); + return 1; + } + return cd_init(nam, args[1], args[2], opts, args + 4, 1); + } case 'g': if (cd_parsed) { - int n = arrlen(args); - - if (n != 8) { - zwarnnam(nam, (n < 8 ? "not enough arguments" : + if (n != 5) { + zwarnnam(nam, (n < 5 ? "not enough arguments" : "too many arguments"), NULL, 0); return 1; } -- cgit 1.4.1