summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSven Wischnowsky <wischnow@users.sourceforge.net>2001-07-25 08:52:34 +0000
committerSven Wischnowsky <wischnow@users.sourceforge.net>2001-07-25 08:52:34 +0000
commiteba59194d72250402bdbb97a866ffea89ec9d7a7 (patch)
tree607dc8f64428fb9f749405c96e7c3e7969739cce
parent6d81779954a9a5ef64c87a21ce131190a1214d7c (diff)
downloadzsh-eba59194d72250402bdbb97a866ffea89ec9d7a7.tar.gz
zsh-eba59194d72250402bdbb97a866ffea89ec9d7a7.zip
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)
-rw-r--r--ChangeLog9
-rw-r--r--Completion/Base/Utility/_describe40
-rw-r--r--Doc/Zsh/compwid.yo12
-rw-r--r--Src/Zle/comp.h3
-rw-r--r--Src/Zle/compcore.c69
-rw-r--r--Src/Zle/complete.c18
-rw-r--r--Src/Zle/complist.c7
-rw-r--r--Src/Zle/compresult.c50
-rw-r--r--Src/Zle/computil.c456
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 <wischnow@zsh.org>
+
+ * 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 <wischnow@zsh.org>
* 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("<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;
-
+ addmatch("<all>", 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;
}