diff options
Diffstat (limited to 'Src')
-rw-r--r-- | Src/Zle/complist.c | 918 | ||||
-rw-r--r-- | Src/Zle/complist.mdd | 3 |
2 files changed, 921 insertions, 0 deletions
diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c new file mode 100644 index 000000000..63bc4c6e3 --- /dev/null +++ b/Src/Zle/complist.c @@ -0,0 +1,918 @@ +/* + * complist.c - completion listing enhancements + * + * This file is part of zsh, the Z shell. + * + * Copyright (c) 1999 Sven Wischnowsky + * All rights reserved. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and to distribute modified versions of this software for any + * purpose, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * In no event shall Sven Wischnowsky or the Zsh Development Group be liable + * to any party for direct, indirect, special, incidental, or consequential + * damages arising out of the use of this software and its documentation, + * even if Sven Wischnowsky and the Zsh Development Group have been advised of + * the possibility of such damage. + * + * Sven Wischnowsky and the Zsh Development Group specifically disclaim any + * warranties, including, but not limited to, the implied warranties of + * merchantability and fitness for a particular purpose. The software + * provided hereunder is on an "as is" basis, and Sven Wischnowsky and the + * Zsh Development Group have no obligation to provide maintenance, + * support, updates, enhancements, or modifications. + * + */ + +#include "complist.mdh" +#include "complist.pro" + + +/* We use the parameters ZLS_COLORS and ZLS_COLOURS in the same way as + * the color ls does. It's just that we don't support the `or' file + * type. */ + + +static Widget w_menuselect; +static Keymap mskeymap; + +/* Indixes into the terminal string arrays. */ + +#define COL_NO 0 +#define COL_FI 1 +#define COL_DI 2 +#define COL_LN 3 +#define COL_PI 4 +#define COL_SO 5 +#define COL_BD 6 +#define COL_CD 7 +#define COL_EX 8 +#define COL_MI 9 +#define COL_LC 10 +#define COL_RC 11 +#define COL_EC 12 +#define COL_MA 13 + +#define NUM_COLS 14 + +/* Names of the terminal strings. */ + +static char *colnames[] = { + "no", "fi", "di", "ln", "pi", "so", "bd", "cd", "ex", "mi", + "lc", "rc", "ec", "ma", NULL +}; + +/* Default values. */ + +static char *defcols[] = { + "0", "0", "1;34", "1;36", "33", "1;35", "1;33", "1;33", "1;32", NULL, + "\033[", "m", NULL, "7" +}; + +/* This describes a terminal string for a filename extension. */ + +typedef struct extcol *Extcol; + +struct extcol { + char *ext; /* the extension */ + char *col; /* the terminal color string */ + Extcol next; /* the next one in the list */ +}; + +/* This holds all terminal strings. */ + +typedef struct listcols *Listcols; + +struct listcols { + char *cols[NUM_COLS]; /* strings for file types */ + Extcol exts; /* strings for extensions */ +}; + +/* This parses the value of a definition (the part after the `='). + * The return value is a pointer to the character after it. */ + +static char * +getcolval(char *s) +{ + char *p; + + for (p = s; *s && *s != ':'; p++, s++) { + if (*s == '\\' && s[1]) { + switch (*++s) { + case 'a': *p = '\007'; break; + case 'n': *p = '\n'; break; + case 'b': *p = '\b'; break; + case 't': *p = '\t'; break; + case 'v': *p = '\v'; break; + case 'f': *p = '\f'; break; + case 'r': *p = '\r'; break; + case 'e': *p = '\033'; break; + case '_': *p = ' '; break; + case '?': *p = '\177'; break; + default: + if (*s >= '0' && *s <= '7') { + int i = STOUC(*s); + + if (*++s >= '0' && *s <= '7') { + i = (i * 8) + STOUC(*s); + if (*++s >= '0' && *s <= '7') + i = (i * 8) + STOUC(*s); + } + *p = (char) i; + } else + *p = *s; + } + } else if (*s == '^') { + if ((s[1] >= '@' && s[1] <= '_') || + (s[1] >= 'a' && s[1] <= 'z')) + *p = (char) (STOUC(*s) & ~0x60); + else if (s[1] == '?') + *p = '\177'; + else { + *p++ = *s; + *p = s[1]; + } + s++; + } else + *p = *s; + } + if (p != s) + *p = '\0'; + return s; +} + +/* This parses one definition. Return value is a pointer to the + * character after it. */ + +static char * +getcoldef(Listcols c, char *s) +{ + if (*s == '*') { + Extcol ec; + char *n, *p; + + /* This is for an extension. */ + + n = ++s; + while (*s && *s != '=') + s++; + if (!*s ) + return s; + *s++ = '\0'; + p = getcolval(s); + if (*n) { + ec = (Extcol) zhalloc(sizeof(*ec)); + ec->ext = n; + ec->col = s; + ec->next = c->exts; + c->exts = ec; + } + if (*p) + *p++ = '\0'; + return p; + } else { + char *n = s, *p, **nn; + int i; + + /* This is for a file type. */ + + while (*s && *s != '=') + s++; + if (!*s) + return s; + *s++ = '\0'; + for (i = 0, nn = colnames; *nn; i++, nn++) + if (!strcmp(n ,*nn)) + break; + p = getcolval(s); + if (*nn) + c->cols[i] = s; + if (*p) + *p++ = '\0'; + return p; + } +} + +/* This initializes the given terminal color structure. */ + +static int +getcols(Listcols c) +{ + char *s; + int i; + + if (!(s = getsparam("ZLS_COLORS")) && + !(s = getsparam("ZLS_COLOURS"))) { + if (!c) + return 1; + for (i = 0; i < NUM_COLS; i++) + c->cols[i] = ""; + + c->exts = NULL; + return 1; + } + if (!c) + return 0; + /* We have one of the parameters, use it. */ + memset(c, 0, sizeof(*c)); + s = dupstring(s); + while (*s) + s = getcoldef(c, s); + + /* Use default values for those that aren't set explicitly. */ + for (i = 0; i < NUM_COLS; i++) + if (!c->cols[i]) + c->cols[i] = defcols[i]; + /* Default for missing files. */ + if (!c->cols[COL_MI]) + c->cols[COL_MI] = c->cols[COL_FI]; + + if (!c->cols[COL_EC]) { + char *e = (char *) zhalloc(strlen(c->cols[COL_LC]) + + strlen(c->cols[COL_NO]) + + strlen(c->cols[COL_RC]) + 1); + + /* If no `ec' was given, we is `<lc><no><rc>' as the default. */ + strcpy(e, c->cols[COL_LC]); + strcat(e, c->cols[COL_NO]); + strcat(e, c->cols[COL_RC]); + c->cols[COL_EC] = e; + } + return 0; +} + +/* Get the terminal color string for the file with the given name and + * file modes. */ + +static char * +getcolstr(Listcols c, char *n, mode_t m) +{ + Extcol e; + + for (e = c->exts; e; e = e->next) + if (strsfx(e->ext, n)) + return e->col; + + if (S_ISDIR(m)) + return c->cols[COL_DI]; + else if (S_ISLNK(m)) + return c->cols[COL_LN]; + else if (S_ISFIFO(m)) + return c->cols[COL_PI]; + else if (S_ISSOCK(m)) + return c->cols[COL_SO]; + else if (S_ISBLK(m)) + return c->cols[COL_BD]; + else if (S_ISCHR(m)) + return c->cols[COL_CD]; + else if (S_ISREG(m) && (m & S_IXUGO)) + return c->cols[COL_EX]; + + return c->cols[COL_FI]; +} + +/* Information about the list shown. */ + +static int noselect, mselect, inselect, mcol, mline, mcols, mlines; +static Cmatch *mmatch, **mtab; +static Cmgroup mgroup, *mgtab; + +/* List the matches. Most of this is just taken from ilistmatches(), + * of course. */ + +static int +complistmatches(Hookdef dummy, Chdata dat) +{ + Cmgroup amatches = dat->matches, g; + 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; + struct listcols col; + + if (minfo.asked == 2) { + showinglist = 0; + return (noselect = 1); + } + 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; + + if (pp) { + /* We have an ylist, lets see, if it contains newlines. */ + while (!nl && *pp) + nl = !!strchr(*pp++, '\n'); + + pp = g->ylist; + if (nl) { + /* Yup, there are newlines, count lines. */ + char *nlptr, *sptr; + + g->flags |= CGF_LINES; + noselect = 1; + while ((sptr = *pp)) { + while (sptr && *sptr) { + nlines += (nlptr = strchr(sptr, '\n')) + ? 1 + (nlptr-sptr)/columns + : strlen(sptr)/columns; + sptr = nlptr ? nlptr+1 : NULL; + } + nlines++; + pp++; + } + nlines--; + } else { + while (*pp) { + if ((l = strlen(*pp)) > longest) + longest = l; + nlist++; + pp++; + } + } + } else { + for (p = g->matches; (m = *p); p++) { + if (!(m->flags & CMF_NOLIST)) { + if ((l = niceztrlen(m->str)) > longest) + longest = l; + nlist++; + } else + noselect = 1; + } + } + if ((e = g->expls)) { + while (*e) { + if ((*e)->count) + nlines += 1 + printfmt((*e)->str, (*e)->count, 0); + e++; + } + } + } + longest += 2 + of; + if ((ncols = (columns + 1) / longest)) { + for (g = amatches; g; g = g->next) + nlines += (g->lcount + ncols - 1) / ncols; + } else { + ncols = 1; + opl = 1; + for (g = amatches; g; g = g->next) { + char **pp = g->ylist; + + if (pp) { + if (!(g->flags & CGF_LINES)) { + while (*pp) { + nlines += 1 + (strlen(*pp) / columns); + pp++; + } + } + } else + for (p = g->matches; (m = *p); p++) + if (!(m->flags & CMF_NOLIST)) + nlines += 1 + ((1 + niceztrlen(m->str)) / columns); + } + } + + /* Maybe we have to ask if the user wants to see the list. */ + if ((!minfo.cur || !minfo.asked) && + ((complistmax && nlist > complistmax) || + (!complistmax && nlines >= lines))) { + int qup; + zsetterm(); + qup = printfmt("zsh: do you wish to see all %n possibilities? ", nlist, 1); + fflush(shout); + if (getzlequery() != 'y') { + if (clearflag) { + putc('\r', shout); + tcmultout(TCUP, TCMULTUP, qup); + if (tccan(TCCLEAREOD)) + tcout(TCCLEAREOD); + tcmultout(TCUP, TCMULTUP, nlnct); + } else + putc('\n', shout); + noselect = 1; + if (minfo.cur) + minfo.asked = 2; + return 1; + } + if (clearflag) { + putc('\r', shout); + tcmultout(TCUP, TCMULTUP, qup); + if (tccan(TCCLEAREOD)) + tcout(TCCLEAREOD); + } else + putc('\n', shout); + settyinfo(&shttyinfo); + if (minfo.cur) + minfo.asked = 1; + } + if (mselect >= 0) { + int i; + + i = ncols * nlines; + free(mtab); + mtab = (Cmatch **) zalloc(i * sizeof(Cmatch **)); + memset(mtab, 0, i * sizeof(Cmatch **)); + free(mgtab); + mgtab = (Cmgroup *) zalloc(i * sizeof(Cmgroup)); + memset(mgtab, 0, i * sizeof(Cmgroup)); + mcols = ncols; + mlines = nlines; + } + /* Now print the matches. */ + g = amatches; + while (g) { + char **pp = g->ylist; + + if ((e = g->expls)) { + while (*e) { + if ((*e)->count) { + if (pnl) { + putc('\n', shout); + pnl = 0; + ml++; + } + ml += printfmt((*e)->str, (*e)->count, 1); + pnl = 1; + } + e++; + } + } + if (pp && *pp) { + if (pnl) { + putc('\n', shout); + pnl = 0; + ml++; + } + if (g->flags & CGF_LINES) { + while (*pp) { + zputs(*pp, shout); + if (*++pp) + putc('\n', shout); + } + } else { + int n = g->lcount, nl = (n + ncols - 1) / ncols, nc = nl, i, a; + char **pq; + + while (n && nl--) { + i = ncols; + mc = 0; + pq = pp; + while (n && i--) { + if (pq - g->ylist >= g->lcount) + break; + zputs(*pq, shout); + if (i) { + a = longest - strlen(*pq); + while (a--) + putc(' ', shout); + } + pq += nc; + n--; + } + if (n) { + putc('\n', shout); + ml++; + } + pp++; + } + } + } else if (g->lcount) { + int n = g->lcount, nl = (n + ncols - 1) / ncols, nc = nl, i, j, a = 0; + int zt; + Cmatch *q; + + if (n && pnl) { + putc('\n', shout); + pnl = 0; + ml++; + } + for (p = skipnolist(g->matches); n && nl--;) { + i = ncols; + mc = 0; + q = p; + while (n && i--) { + fputs(col.cols[COL_LC], shout); + if (!(m = *q)) { + fputs(col.cols[COL_MI], shout); + fputs(col.cols[COL_RC], shout); + a = longest - 2; + while (a--) + putc(' ', shout); + fputs(col.cols[COL_EC], shout); + break; + } + hasm = 1; + if (mselect >= 0) { + mtab[mc + (ncols * ml)] = q; + mgtab[mc + (ncols * ml)] = g; + } + if (m->gnum == mselect) { + mcol = mc; + mline = ml; + mmatch = q; + mgroup = g; + cc = COL_MA; + } else + cc = -1; + if (m->flags & CMF_FILE) { + struct stat buf; + char *pb; + + pb = (char *) zhalloc((m->prpre ? strlen(m->prpre) : 0) + + 3 + strlen(m->str)); + sprintf(pb, "%s%s", (m->prpre ? m->prpre : "./"), + m->str); + + zt = ztat(pb, &buf, 1); + if (cc >= 0) + fputs(col.cols[cc], shout); + else if (zt) + fputs(col.cols[COL_NO], shout); + else + fputs(getcolstr(&col, pb, buf.st_mode), shout); + fputs(col.cols[COL_RC], shout); + nicezputs(m->str, shout); + if (zt) + putc(' ', shout); + else + putc(file_type(buf.st_mode), shout); + } else { + fputs(col.cols[cc >= 0 ? cc : COL_NO], shout); + fputs(col.cols[COL_RC], shout); + nicezputs(m->str, shout); + if (of) + putc(' ', shout); + } + a = longest - niceztrlen(m->str) - 2 - of; + while (a--) + putc(' ', shout); + fputs(col.cols[COL_EC], shout); + if (i) { + fputs(col.cols[COL_LC], shout); + fputs(col.cols[COL_NO], shout); + fputs(col.cols[COL_RC], shout); + fputs(" ", shout); + fputs(col.cols[COL_EC], shout); + } + if (--n) + for (j = nc; j && *q; j--) + q = skipnolist(q + 1); + mc++; + } + if (i > 0) { + fputs(col.cols[COL_LC], shout); + fputs(col.cols[COL_MI], shout); + fputs(col.cols[COL_RC], shout); + a = longest - 2; + while (a--) + putc(' ', shout); + fputs(col.cols[COL_EC], shout); + } + if (n) { + putc('\n', shout); + ml++; + if (n && nl) + p = skipnolist(p + 1); + } + } + } + if (g->lcount) + 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); + if (!hasm || nlines >= lines) + noselect = 1; + return noselect; +} + +typedef struct menustack *Menustack; + +struct menustack { + Menustack prev; + char *line; + int cs; + struct menuinfo info; +}; + +static int +domenuselect(Hookdef dummy, Chdata dat) +{ + Cmatch **p; + Cmgroup *pg; + Thingy cmd; + Menustack u = NULL; + int i = 0; + char *s; + + if (getcols(NULL) || (dummy && (!(s = getsparam("SELECTMIN")) || + (dat && dat->num < atoi(s))))) + return 1; + + selectlocalmap(mskeymap); + noselect = 0; + mselect = (*(minfo.cur))->gnum; + for (;;) { + showinglist = -2; + zrefresh(); + inselect = 1; + if (noselect) + break; + if (!i) { + i = mcols * mlines; + while (i--) + if (mtab[i]) + break; + if (!i) + break; + i = 1; + } + p = mtab + mcol + (mline * mcols); + pg = mgtab + mcol + (mline * mcols); + minfo.cur = *p; + minfo.group = *pg; + + getk: + + if (!(cmd = getkeycmd()) || cmd == Th(z_sendbreak) || + cmd == Th(z_acceptline)) + break; + else if (cmd == Th(z_acceptandhold) || + cmd == Th(z_acceptandmenucomplete)) { + Menustack s = (Menustack) zhalloc(sizeof(*s)); + + s->prev = u; + u = s; + s->line = dupstring((char *) line); + s->cs = cs; + memcpy(&(s->info), &minfo, sizeof(struct menuinfo)); + acceptlast(); + do_menucmp(0); + mselect = (*(minfo.cur))->gnum; + continue; + } else if (cmd == Th(z_undo)) { + int l; + + if (!u) + goto getk; + + cs = 0; + foredel(ll); + spaceinline(l = strlen(u->line)); + strncpy((char *) line, u->line, l); + cs = u->cs; + memcpy(&minfo, &(u->info), sizeof(struct menuinfo)); + p = &(minfo.cur); + u = u->prev; + } else if (cmd == Th(z_redisplay)) { + redisplay(zlenoargs); + continue; + } else if (cmd == Th(z_clearscreen)) { + clearscreen(zlenoargs); + continue; + } else if (cmd == Th(z_downhistory) || + cmd == Th(z_downlineorhistory) || + cmd == Th(z_downlineorsearch) || + cmd == Th(z_vidownlineorhistory)) { + do { + if (mline == mlines - 1) { + p -= mline * mcols; + mline = 0; + } else { + mline++; + p += mcols; + } + } while (!*p); + } else if (cmd == Th(z_uphistory) || + cmd == Th(z_uplineorhistory) || + cmd == Th(z_uplineorsearch) || + cmd == Th(z_viuplineorhistory)) { + do { + if (!mline) { + mline = mlines - 1; + p += mline * mcols; + } else { + mline--; + p -= mcols; + } + } while (!*p); + } else if (cmd == Th(z_forwardchar) || cmd == Th(z_viforwardchar)) { + do { + if (mcol == mcols - 1) { + p -= mcol; + mcol = 0; + } else { + mcol++; + p++; + } + } while (!*p); + } else if (cmd == Th(z_backwardchar) || cmd == Th(z_vibackwardchar)) { + do { + if (!mcol) { + mcol = mcols - 1; + p += mcol; + } else { + mcol--; + p--; + } + } while (!*p); + } else if (cmd == Th(z_beginningofbufferorhistory) || + cmd == Th(z_beginningofline) || + cmd == Th(z_beginningoflinehist) || + cmd == Th(z_vibeginningofline)) { + p -= mcol; + mcol = 0; + while (!*p) { + mcol++; + p++; + } + } else if (cmd == Th(z_endofbufferorhistory) || + cmd == Th(z_endofline) || + cmd == Th(z_endoflinehist) || + cmd == Th(z_viendofline)) { + p += mcols - mcol - 1; + mcol = mcols - 1; + while (!*p) { + mcol--; + p--; + } + } else if (cmd == Th(z_forwardword) || + cmd == Th(z_emacsforwardword) || + cmd == Th(z_viforwardword) || + cmd == Th(z_viforwardwordend)) { + Cmgroup g = *pg; + int ol = mline; + + do { + if (mline == mlines - 1) { + p -= mline * mcols; + pg -= mline * mcols; + mline = 0; + } else { + mline++; + p += mcols; + pg += mcols; + } + } while (ol != mline && (*pg == g || !*pg)); + } else if (cmd == Th(z_backwardword) || + cmd == Th(z_emacsbackwardword) || + cmd == Th(z_vibackwardword)) { + Cmgroup g = *pg; + int ol = mline; + + do { + if (!mline) { + mline = mlines - 1; + p += mline * mcols; + pg += mline * mcols; + } else { + mline--; + p -= mcols; + pg -= mcols; + } + } while (ol != mline && (*pg == g || !*pg)); + } else if (cmd == Th(z_completeword) || + cmd == Th(z_expandorcomplete) || + cmd == Th(z_expandorcompleteprefix) || + cmd == Th(z_menucomplete) || + cmd == Th(z_menuexpandorcomplete) || + !strcmp(cmd->nam, "menu-select") || + !strcmp(cmd->nam, "complete-word") || + !strcmp(cmd->nam, "expand-or-complete") || + !strcmp(cmd->nam, "expand-or-complete-prefix") || + !strcmp(cmd->nam, "menu-complete") || + !strcmp(cmd->nam, "menu-expand-or-complete")) { + do_menucmp(0); + mselect = (*(minfo.cur))->gnum; + continue; + } else if (cmd == Th(z_reversemenucomplete) || + !strcmp(cmd->nam, "reverse-menu-complete")) { + reversemenucomplete(zlenoargs); + mselect = (*(minfo.cur))->gnum; + continue; + } else { + ungetkeycmd(); + break; + } + do_single(**p); + mselect = (**p)->gnum; + } + selectlocalmap(NULL); + mselect = -1; + inselect = 0; + if (!noselect) { + showinglist = -2; + zrefresh(); + } + return noselect; +} + +/* The widget function. */ + +static int +menuselect(char **args) +{ + int d = 0; + + if (!minfo.cur) { + menucomplete(args); + if ((minfo.cur && minfo.asked == 2) || getsparam("ZLS_SELECT")) + return 0; + d = 1; + } + if (minfo.cur && (minfo.asked == 2 || domenuselect(NULL, NULL)) && !d) + menucomplete(args); + + return 0; +} + +/**/ +int +setup_complist(Module m) +{ + return 0; +} + +/**/ +int +boot_complist(Module m) +{ + mtab = NULL; + mgtab = NULL; + mselect = -1; + inselect = 0; + + w_menuselect = addzlefunction("menu-select", menuselect, + ZLE_MENUCMP|ZLE_KEEPSUFFIX|ZLE_ISCOMP); + if (!w_menuselect) { + zwarnnam(m->nam, "name clash when adding ZLE function `menu-select'", + NULL, 0); + return -1; + } + addhookfunc("list_matches", (Hookfn) complistmatches); + addhookfunc("menu_start", (Hookfn) domenuselect); + mskeymap = newkeymap(NULL, "menuselect"); + linkkeymap(mskeymap, "menuselect", 1); + bindkey(mskeymap, "\t", refthingy(t_completeword), NULL); + bindkey(mskeymap, "\n", refthingy(t_acceptline), NULL); + bindkey(mskeymap, "\r", refthingy(t_acceptline), NULL); + bindkey(mskeymap, "\33[A", refthingy(t_uplineorhistory), NULL); + bindkey(mskeymap, "\33[B", refthingy(t_downlineorhistory), NULL); + bindkey(mskeymap, "\33[C", refthingy(t_forwardchar), NULL); + bindkey(mskeymap, "\33[D", refthingy(t_backwardchar), NULL); + bindkey(mskeymap, "\33OA", refthingy(t_uplineorhistory), NULL); + bindkey(mskeymap, "\33OB", refthingy(t_downlineorhistory), NULL); + bindkey(mskeymap, "\33OC", refthingy(t_forwardchar), NULL); + bindkey(mskeymap, "\33OD", refthingy(t_backwardchar), NULL); + return 0; +} + +#ifdef MODULE + +/**/ +int +cleanup_complist(Module m) +{ + free(mtab); + free(mgtab); + + deletezlefunction(w_menuselect); + deletehookfunc("list_matches", (Hookfn) complistmatches); + deletehookfunc("menu_start", (Hookfn) domenuselect); + unlinkkeymap("menuselect", 1); + return 0; +} + +/**/ +int +finish_complist(Module m) +{ + return 0; +} + +#endif diff --git a/Src/Zle/complist.mdd b/Src/Zle/complist.mdd new file mode 100644 index 000000000..8ea60b0a8 --- /dev/null +++ b/Src/Zle/complist.mdd @@ -0,0 +1,3 @@ +moddeps="comp1 zle" + +objects="complist.o" |