From 20d67907c95265356b51dbdce8ecc0c1ede9e66b Mon Sep 17 00:00:00 2001 From: Tanaka Akira Date: Thu, 15 Apr 1999 18:11:42 +0000 Subject: zsh-3.1.5-pws-5 --- Src/Zle/comp1.c | 44 +++- Src/Zle/comp1.export | 13 ++ Src/Zle/compctl.c | 582 +++++++++++++++++++++++++++++++++++++++++++++++--- Src/Zle/compctl.mdd | 4 +- Src/Zle/iwidgets.list | 16 +- Src/Zle/zle.h | 18 +- Src/Zle/zle_keymap.c | 4 +- Src/Zle/zle_main.c | 28 ++- Src/Zle/zle_refresh.c | 105 ++++----- Src/Zle/zle_thingy.c | 50 ++++- Src/Zle/zle_tricky.c | 448 ++++++++++++++++++++++++++++++++++---- 11 files changed, 1152 insertions(+), 160 deletions(-) (limited to 'Src/Zle') diff --git a/Src/Zle/comp1.c b/Src/Zle/comp1.c index a0c013901..42bc92bb2 100644 --- a/Src/Zle/comp1.c +++ b/Src/Zle/comp1.c @@ -41,7 +41,7 @@ struct compctl cc_compos, cc_default, cc_first, cc_dummy; /**/ Cmlist cmatcher; -/* pointers to functions required by zle */ +/* pointers to functions required by zle and defined by compctl */ /**/ void (*printcompctlptr) _((char *, Compctl, int, int)); @@ -49,6 +49,24 @@ void (*printcompctlptr) _((char *, Compctl, int, int)); /**/ Compctl (*compctl_widgetptr) _((char *, char **)); +/**/ +void (*makecompparamsptr) _((void)); + +/* pointers to functions required by compctl and defined by zle */ + +/**/ +void (*addmatchesptr) _((char *, char *, char *, char *, char *, char *, char *, int, int, int, int, int, char **)); + +/**/ +char *(*comp_strptr) _((int*,int*)); + +/**/ +int (*getcpatptr) _((char *, int, char *, int)); + +/**/ +void (*makecomplistcallptr) _((Compctl)); + + /* Hash table for completion info for commands */ /**/ @@ -72,6 +90,23 @@ char **clwords; /**/ int incompctlfunc; +/* != 0 if we are in a new style completion function */ + +/**/ +int incompfunc; + +/* global variables for shell parameters in new style completion */ + +/**/ +long compcurrent, + compnmatches; + +/**/ +char *compcontext, + *compcommand, + *compprefix, + *compsuffix, + *compiprefix; /* This variable and the functions rembslash() and quotename() came from * * zle_tricky.c, but are now used in compctl.c, too. */ @@ -443,6 +478,8 @@ setup_comp1(Module m) cc_first.refc = 10000; cc_first.mask = 0; cc_first.mask2 = CC_CCCONT; + compcontext = compcommand = compprefix = compsuffix = + compiprefix = NULL; return 0; } @@ -469,6 +506,11 @@ finish_comp1(Module m) deletehashtable(compctltab); zfree(clwords, clwsize * sizeof(char *)); compctlreadptr = fallback_compctlread; + zsfree(compcontext); + zsfree(compcommand); + zsfree(compprefix); + zsfree(compiprefix); + zsfree(compsuffix); return 0; } diff --git a/Src/Zle/comp1.export b/Src/Zle/comp1.export index 1ac9195df..c90161740 100644 --- a/Src/Zle/comp1.export +++ b/Src/Zle/comp1.export @@ -1,4 +1,5 @@ #! +addmatchesptr cc_compos cc_default cc_dummy @@ -8,14 +9,26 @@ clwords clwpos clwsize cmatcher +compcommand +compcontext compctl_widgetptr compctltab +compcurrent +compiprefix +compnmatches +compprefix +comp_strptr +compsuffix freecmatcher freecmlist freecompcond freecompctl +getcpatptr incompctlfunc +incompfunc instring +makecomplistcallptr +makecompparamsptr patcomps printcompctlptr quotename diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c index 4d192fef8..1913d3828 100644 --- a/Src/Zle/compctl.c +++ b/Src/Zle/compctl.c @@ -373,7 +373,7 @@ parse_class(Cpattern p, unsigned char *s, unsigned char e) /**/ static int -get_compctl(char *name, char ***av, Compctl cc, int first, int isdef) +get_compctl(char *name, char ***av, Compctl cc, int first, int isdef, int cl) { /* Parse the basic flags for completion: * first is a flag that we are not in extended completion, @@ -394,12 +394,17 @@ get_compctl(char *name, char ***av, Compctl cc, int first, int isdef) if(argv[0] && argv[0][0] == '-') argv++; *av = argv; - freecompctl(cc); - cclist = COMP_REMOVE; - return 0; + if (cl) + return 1; + else { + freecompctl(cc); + cclist = COMP_REMOVE; + return 0; + } } memset((void *)&cct, 0, sizeof(cct)); + cct.mask2 = CC_CCCONT; /* Loop through the flags until we have no more: * * those with arguments are not properly allocated yet, * @@ -505,6 +510,10 @@ get_compctl(char *name, char ***av, Compctl cc, int first, int isdef) { char *p; + if (cl) { + zerrnam(name, "illegal option -%c", NULL, **argv); + return 1; + } if ((*argv)[1]) { p = (*argv) + 1; *argv = "" - 1; @@ -516,26 +525,28 @@ get_compctl(char *name, char ***av, Compctl cc, int first, int isdef) p = *++argv; *argv = "" - 1; } - while (*p) { - switch (*p) { - case '+': - cct.mask2 |= CC_XORCONT; - break; - case 'c': - cct.mask2 |= CC_CCCONT; - break; - case '-': - cct.mask2 |= CC_PATCONT; - break; - case 'x': - cct.mask2 |= CC_DEFCONT; - break; - default: - zwarnnam(name, "invalid retry specification character `%c'", - NULL, *p); - return 1; - } - p++; + switch (*p) { + case '+': + cct.mask2 = CC_XORCONT; + break; + case 'n': + cct.mask2 = 0; + break; + case '-': + cct.mask2 = CC_PATCONT; + break; + case 'x': + cct.mask2 = CC_DEFCONT; + break; + default: + zwarnnam(name, "invalid retry specification character `%c'", + NULL, *p); + return 1; + } + if (p[1]) { + zwarnnam(name, "too many retry specification characters: `%s'", + p + 1, 0); + return 1; } } break; @@ -645,7 +656,10 @@ get_compctl(char *name, char ***av, Compctl cc, int first, int isdef) } break; case 'l': - if ((*argv)[1]) { + if (cl) { + zerrnam(name, "illegal option -%c", NULL, **argv); + return 1; + } else if ((*argv)[1]) { cct.subcmd = (*argv) + 1; *argv = "" - 1; } else if (!argv[1]) { @@ -745,6 +759,10 @@ get_compctl(char *name, char ***av, Compctl cc, int first, int isdef) *argv = "" - 1; break; case 'C': + if (cl) { + zerrnam(name, "illegal option -%c", NULL, **argv); + return 1; + } if (first && !hx) { cclist |= COMP_COMMAND; } else { @@ -754,6 +772,10 @@ get_compctl(char *name, char ***av, Compctl cc, int first, int isdef) } break; case 'D': + if (cl) { + zerrnam(name, "illegal option -%c", NULL, **argv); + return 1; + } if (first && !hx) { isdef = 1; cclist |= COMP_DEFAULT; @@ -764,7 +786,11 @@ get_compctl(char *name, char ***av, Compctl cc, int first, int isdef) } break; case 'T': - if (first && !hx) { + if (cl) { + zerrnam(name, "illegal option -%c", NULL, **argv); + return 1; + } + if (first && !hx) { cclist |= COMP_FIRST; } else { zwarnnam(name, "misplaced first completion (-T) flag", @@ -773,6 +799,10 @@ get_compctl(char *name, char ***av, Compctl cc, int first, int isdef) } break; case 'L': + if (cl) { + zerrnam(name, "illegal option -%c", NULL, **argv); + return 1; + } if (!first || hx) { zwarnnam(name, "illegal use of -L flag", NULL, 0); return 1; @@ -780,6 +810,10 @@ get_compctl(char *name, char ***av, Compctl cc, int first, int isdef) cclist |= COMP_LIST; break; case 'x': + if (cl) { + zerrnam(name, "extended completion not allowed", NULL, 0); + return 1; + } if (!argv[1]) { zwarnnam(name, "condition expected after -%c", NULL, **argv); @@ -811,6 +845,10 @@ get_compctl(char *name, char ***av, Compctl cc, int first, int isdef) if (*++argv && (!ready || ready == 2) && **argv == '+' && !argv[0][1]) { + if (cl) { + zerrnam(name, "xor'ed completion illegal", NULL, 0); + return 1; + } /* There's an alternative (+) completion: assign * what we have so far before moving on to that. */ @@ -835,6 +873,7 @@ get_compctl(char *name, char ***av, Compctl cc, int first, int isdef) cc->xor = (Compctl) zcalloc(sizeof(*cc)); cc = cc->xor; memset((void *)&cct, 0, sizeof(cct)); + cct.mask2 = CC_CCCONT; } } } @@ -1084,7 +1123,7 @@ get_xcompctl(char *name, char ***av, Compctl cc, int isdef) (*next)->cond = m; argv++; /* End of the condition; get the flags that go with it. */ - if (get_compctl(name, &argv, *next, 0, isdef)) + if (get_compctl(name, &argv, *next, 0, isdef, 0)) return 1; if ((!argv || !*argv) && (cclist & COMP_SPECIAL)) /* default, first, or command completion finished */ @@ -1362,17 +1401,16 @@ printcompctl(char *s, Compctl cc, int printflags, int ispat) t >>= 1; } } - if (flags2 & (CC_XORCONT | CC_CCCONT | CC_PATCONT | CC_DEFCONT)) { + if (flags2 & (CC_XORCONT | CC_PATCONT | CC_DEFCONT)) { printf(" -t"); if (flags2 & CC_XORCONT) putchar('+'); - if (flags2 & CC_CCCONT) - putchar('c'); if (flags2 & CC_PATCONT) putchar('-'); if (flags2 & CC_DEFCONT) putchar('x'); - } + } else if (!(flags2 & CC_CCCONT)) + printf(" -tn"); /* now flags with arguments */ printif(cc->mstr, 'M'); if (flags2 & CC_NOSORT) @@ -1518,7 +1556,7 @@ bin_compctl(char *name, char **argv, char *ops, int func) return ret - 1; cc = (Compctl) zcalloc(sizeof(*cc)); - if (get_compctl(name, &argv, cc, 1, 0)) { + if (get_compctl(name, &argv, cc, 1, 0, 0)) { freecompctl(cc); return 1; } @@ -1610,7 +1648,7 @@ compctl_widget(char *name, char **argv) cclist = 0; showmask = 0; - if (get_compctl(name, &argv, cc, 1, 0)) { + if (get_compctl(name, &argv, cc, 1, 0, 0)) { freecompctl(cc); return NULL; } @@ -1632,8 +1670,478 @@ compctl_widget(char *name, char **argv) return cc; } +/**/ +static int +bin_complist(char *name, char **argv, char *ops, int func) +{ + Compctl cc; + int ret = 0; + + if (!incompfunc) { + zerrnam(name, "can only be called from completion function", NULL, 0); + return 1; + } + cc = (Compctl) zcalloc(sizeof(*cc)); + cclist = 0; + showmask = 0; + + if (get_compctl(name, &argv, cc, 1, 0, 1)) + ret = 1; + else if (*argv) { + zerrnam(name, "command names illegal", NULL, 0); + ret = 1; + } else + makecomplistcallptr(cc); + + freecompctl(cc); + return ret; +} + +/**/ +static int +bin_compadd(char *name, char **argv, char *ops, int func) +{ + char *p, **sp, *e; + char *ipre = NULL, *ppre = NULL, *psuf = NULL, *prpre = NULL; + char *pre = NULL, *suf = NULL, *group = NULL; + int f = 0, q = 0, m = 0, ns = 0, a = 0; + + if (!incompfunc) { + zerrnam(name, "can only be called from completion function", NULL, 0); + return 1; + } + for (; *argv && **argv == '-'; argv++) { + for (p = *argv + 1; *p; p++) { + sp = NULL; + switch (*p) { + case 'q': + f |= CMF_REMOVE; + break; + case 'Q': + q = 1; + break; + case 'f': + f |= CMF_FILE; + break; + case 'n': + f |= CMF_NOLIST; + break; + case 'U': + m = 1; + break; + case 'P': + sp = ⪯ + e = "string expected after -%c"; + break; + case 'S': + sp = &suf; + e = "string expected after -%c"; + break; + case 'J': + sp = &group; + e = "group name expected after -%c"; + break; + case 'V': + if (!group) + ns = 1; + sp = &group; + e = "group name expected after -%c"; + break; + case 'i': + sp = &ipre; + e = "string expected after -%c"; + break; + case 'p': + sp = &ppre; + e = "string expected after -%c"; + break; + case 's': + sp = &psuf; + e = "string expected after -%c"; + break; + case 'W': + sp = &prpre; + e = "string expected after -%c"; + break; + case 'a': + a = 1; + break; + case '-': + argv++; + goto ca_args; + default: + zerrnam(name, "bad option: -%c", NULL, *p); + return 1; + } + if (sp) { + if (*sp) { + zerrnam(name, "doubled option: -%c", NULL, *p); + return 1; + } + if (p[1]) { + *sp = p + 1; + p = "" - 1; + } else if (argv[1]) { + *sp = *++argv; + p = "" - 1; + } else { + zerrnam(name, e, NULL, *p); + return 1; + } + } + } + } + ca_args: + if (!*argv) { + zerrnam(name, "missing completions", NULL, 0); + return 1; + } + addmatchesptr(ipre, ppre, psuf, prpre, pre, suf, group, + f, q, m, ns, a, argv); + return 0; +} + +#define VAR(X) ((void *) (&(X))) +static struct compparam { + char *name; + int type; + void *var; +} compparams[] = { + { "CURRENT", PM_INTEGER, VAR(compcurrent) }, + { "CONTEXT", PM_SCALAR, VAR(compcontext) }, + { "COMMAND", PM_SCALAR, VAR(compcommand) }, + { "PREFIX", PM_SCALAR, VAR(compprefix) }, + { "SUFFIX", PM_SCALAR, VAR(compsuffix) }, + { "IPREFIX", PM_SCALAR, VAR(compiprefix) }, + { "NMATCHES", PM_INTEGER, VAR(compnmatches) }, + { NULL, 0, NULL } +}; + +/**/ +void makecompparams(void) +{ + struct compparam *cp; + + for (cp = compparams; cp->name; cp++) { + Param pm = createparam(cp->name, cp->type | PM_SPECIAL); + if (!pm) + pm = (Param) paramtab->getnode(paramtab, cp->name); + DPUTS(!pm, "param not set in makecompparams"); + + pm->level = locallevel; + pm->u.data = cp->var; + switch(PM_TYPE(cp->type)) { + case PM_SCALAR: + pm->sets.cfn = strvarsetfn; + pm->gets.cfn = strvargetfn; + break; + case PM_INTEGER: + pm->sets.ifn = intvarsetfn; + pm->gets.ifn = intvargetfn; + break; + } + pm->unsetfn = compunsetfn; + } +} + +/**/ +static void +compunsetfn(Param pm, int exp) +{ + if (exp) + stdunsetfn(pm, exp); +} + +/**/ +static int +comp_wrapper(List list, FuncWrap w, char *name) +{ + if (!incompfunc) + return 1; + else { + char *octxt, *ocmd, *opre, *osuf, *oipre; + long ocur; + + ocur = compcurrent; + octxt = dupstring(compcontext); + ocmd = dupstring(compcommand); + opre = dupstring(compprefix); + osuf = dupstring(compsuffix); + oipre = dupstring(compiprefix); + + runshfunc(list, w, name); + + compcurrent = ocur; + zsfree(compcontext); + compcontext = ztrdup(octxt); + zsfree(compcommand); + compcommand = ztrdup(ocmd); + zsfree(compprefix); + compprefix = ztrdup(opre); + zsfree(compsuffix); + compsuffix = ztrdup(osuf); + zsfree(compiprefix); + compiprefix = ztrdup(oipre); + + return 0; + } +} + +/**/ +static void +ignore_prefix(int l) +{ + char *o, sav = compprefix[l]; + + compprefix[l] = '\0'; + o = compiprefix; + compiprefix = tricat(o, compprefix, ""); + zsfree(o); + compprefix[l] = sav; + o = compprefix; + compprefix = ztrdup(o + l); + zsfree(o); +} + +/**/ +static int +comp_check(void) +{ + if (!incompfunc) { + zerr("condition can only be used in completion function", NULL, 0); + return 0; + } + return 1; +} + +/**/ +static void +restrict_range(int b, int e) +{ + int i = e - b; + char **p = (char **) zcalloc((i + 1) * sizeof(char *)), **q, **pp; + + for (q = p, pp = pparams + b + 1; i; i--, q++, pp++) + *q = ztrdup(*pp); + zsfree(compcommand); + compcommand = ztrdup(pparams[b]); + freearray(pparams); + pparams = p; + zsfree(compcontext); + if ((compcurrent -= b + 1)) + compcontext = ztrdup("arg"); + else + compcontext = ztrdup("cmd"); +} + +/**/ +static int +cond_prefix(char **a, int id) +{ + if (comp_check()) + return strpfx(cond_str(a, 0), compprefix); + return 0; +} + +/**/ +static int +cond_iprefix(char **a, int id) +{ + if (comp_check()) { + char *s = cond_str(a, 0); + + if (strpfx(s, compprefix)) { + ignore_prefix(strlen(s)); + return 1; + } + } + return 0; +} + +/**/ +static int +cond_position(char **a, int id) +{ + if (comp_check()) { + int b = cond_val(a, 0), e = (a[1] ? cond_val(a, 1) : b); + int l = arrlen(pparams), t, i = compcurrent - 1; + + if (b > 0) + b--; + if (e > 0) + e--; + if (b < 0) + b += l; + if (e < 0) + e += l; + t = (b >= 0 && e >= 0 && i >= b && i <= e && b <= e); + + if (t && a[1]) { + if (b > l) + b = l; + if (e > l) + e = l; + restrict_range(b, e); + } + return t; + } + return 0; +} + +/**/ +static int +cond_word(char **a, int id) +{ + if (comp_check()) { + int o = ((id & 2) ? compcurrent : 0) + cond_val(a, 0); + int l = arrlen(pparams); + char *s; + + if (o < 0) + o += l; + + o--; + if (o < 0 || o >= l) + return 0; + + s = pparams[o]; + return ((id & 1) ? cond_match(a, 1, s) : !strcmp(s, cond_str(a, 1))); + } + return 0; +} + +/**/ +static int +cond_strcl(char **a, int id) +{ + if (comp_check()) { + char *s; + int i; + + if (a[1]) { + s = cond_str(a, 1); + i = cond_val(a, 0); + } else { + s = cond_str(a, 0); + i = -1; + } + if (!getcpatptr) { + zerr("zle not loaded, zle condition not available", NULL, 0); + return 1; + } + i = getcpatptr(comp_strptr(NULL, NULL), i, s, id); + if (i != -1) { + ignore_prefix(i); + return 1; + } + } + return 0; +} + +/**/ +static int +cond_words(char **a, int id) +{ + if (comp_check()) { + int b = cond_val(a, 0), e = (a[1] ? cond_val(a, 1) : -1); + int l = arrlen(pparams); + + return (l >= b && l <= e); + } + return 0; +} + +/**/ +static int +cond_range(char **a, int id) +{ + if (comp_check()) { + char *s, **p; + int i, l = arrlen(pparams), t = 0, b = 0, e = l - 1; + Comp c; + + i = compcurrent - 1; + if (i < 0 || i >= l) + return 0; + + if (id & 1) { + s = a[0]; + singsub(&s); + c = parsereg(s); + } else + s = cond_str(a, 0); + + for (i--, p = pparams + i; i >= 0; p--, i--) { + if (((id & 1) ? domatch(*p, c, 0) : !strcmp(*p, s))) { + b = i + 1; + t = 1; + break; + } + } + if (t && (id & 2)) { + int tt = 0; + + if (id & 1) { + s = a[1]; + singsub(&s); + c = parsereg(s); + } else + s = cond_str(a, 1); + + for (i++, p = pparams + i; i < l; p++, i++) { + if (((id & 1) ? domatch(*p, c, 0) : !strcmp(*p, s))) { + e = i - 1; + tt = 1; + break; + } + } + if (tt && i < compcurrent) + t = 0; + } + if (e < b) + t = 0; + if (t) + restrict_range(b, e); + return t; + } + return 0; +} + +/**/ +static int +cond_nmatches(char **a, int id) +{ + if (comp_check()) + return compnmatches == cond_val(a, 0); + return 0; +} + static struct builtin bintab[] = { BUILTIN("compctl", 0, bin_compctl, 0, -1, 0, NULL, NULL), + BUILTIN("complist", 0, bin_complist, 1, -1, 0, NULL, NULL), + BUILTIN("compadd", 0, bin_compadd, 1, -1, 0, NULL, NULL), +}; + +static struct conddef cotab[] = { + CONDDEF("prefix", 0, cond_prefix, 1, 1, 0), + CONDDEF("iprefix", 0, cond_iprefix, 1, 1, 0), + CONDDEF("position", 0, cond_position, 1, 2, 0), + CONDDEF("word", 0, cond_word, 2, 2, 0), + CONDDEF("mword", 0, cond_word, 2, 2, 1), + CONDDEF("current", 0, cond_word, 2, 2, 2), + CONDDEF("mcurrent", 0, cond_word, 2, 2, 3), + CONDDEF("string", 0, cond_strcl, 1, 2, 0), + CONDDEF("class", 0, cond_strcl, 1, 2, 1), + CONDDEF("words", 0, cond_words, 1, 2, 0), + CONDDEF("between", 0, cond_range, 2, 2, 2), + CONDDEF("mbetween", 0, cond_range, 2, 2, 3), + CONDDEF("after", 0, cond_range, 1, 1, 0), + CONDDEF("mafter", 0, cond_range, 1, 1, 1), + CONDDEF("nmatches", 0, cond_nmatches, 1, 1, 0), +}; + +static struct funcwrap wrapper[] = { + WRAPDEF(comp_wrapper), }; /**/ @@ -1643,6 +2151,7 @@ setup_compctl(Module m) compctltab->printnode = printcompctlp; printcompctlptr = printcompctl; compctl_widgetptr = compctl_widget; + makecompparamsptr = makecompparams; return 0; } @@ -1650,7 +2159,9 @@ setup_compctl(Module m) int boot_compctl(Module m) { - if(!addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab))) + if(!(addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)) | + addconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab)) | + !addwrapper(m, wrapper))) return 1; return 0; } @@ -1662,6 +2173,8 @@ int cleanup_compctl(Module m) { deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); + deleteconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab)); + deletewrapper(m, wrapper); return 0; } @@ -1672,6 +2185,7 @@ finish_compctl(Module m) compctltab->printnode = NULL; printcompctlptr = NULL; compctl_widgetptr = NULL; + makecompparamsptr = NULL; return 0; } diff --git a/Src/Zle/compctl.mdd b/Src/Zle/compctl.mdd index c83ecda29..48aabe38a 100644 --- a/Src/Zle/compctl.mdd +++ b/Src/Zle/compctl.mdd @@ -1,5 +1,7 @@ moddeps="comp1" -autobins="compctl" +autobins="compctl complist compadd" + +autoprefixconds="prefix iprefix position word mword current mcurrent string class words between mbetween after mafter nmatches" objects="compctl.o" diff --git a/Src/Zle/iwidgets.list b/Src/Zle/iwidgets.list index 52e70fad5..12425d872 100644 --- a/Src/Zle/iwidgets.list +++ b/Src/Zle/iwidgets.list @@ -25,11 +25,11 @@ "beginning-of-line-hist", beginningoflinehist, 0 "capitalize-word", capitalizeword, 0 "clear-screen", clearscreen, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_NOTCOMMAND -"complete-word", completeword, ZLE_MENUCMP | ZLE_KEEPSUFFIX +"complete-word", completeword, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP "copy-prev-word", copyprevword, 0 "copy-region-as-kill", copyregionaskill, ZLE_KEEPSUFFIX "delete-char", deletechar, ZLE_KEEPSUFFIX -"delete-char-or-list", deletecharorlist, ZLE_MENUCMP | ZLE_KEEPSUFFIX +"delete-char-or-list", deletecharorlist, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP "delete-word", deleteword, ZLE_KEEPSUFFIX "describe-key-briefly", describekeybriefly, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL "digit-argument", digitargument, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_NOTCOMMAND @@ -48,8 +48,8 @@ "execute-named-cmd", NULL, 0 "expand-cmd-path", expandcmdpath, 0 "expand-history", expandhistory, 0 -"expand-or-complete", expandorcomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX -"expand-or-complete-prefix", expandorcompleteprefix, ZLE_MENUCMP | ZLE_KEEPSUFFIX +"expand-or-complete", expandorcomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP +"expand-or-complete-prefix", expandorcompleteprefix, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP "expand-word", expandword, 0 "forward-char", forwardchar, 0 "forward-word", forwardword, 0 @@ -68,11 +68,11 @@ "kill-region", killregion, ZLE_KILL | ZLE_KEEPSUFFIX "kill-whole-line", killwholeline, ZLE_KILL | ZLE_KEEPSUFFIX "kill-word", killword, ZLE_KILL | ZLE_KEEPSUFFIX -"list-choices", listchoices, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL +"list-choices", listchoices, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_ISCOMP "list-expand", listexpand, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL "magic-space", magicspace, 0 -"menu-complete", menucomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX -"menu-expand-or-complete", menuexpandorcomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX +"menu-complete", menucomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP +"menu-expand-or-complete", menuexpandorcomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP "neg-argument", negargument, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_NOTCOMMAND "overwrite-mode", overwritemode, 0 "pound-insert", poundinsert, 0 @@ -84,7 +84,7 @@ "quote-region", quoteregion, 0 "redisplay", redisplay, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL "redo", redo, 0 -"reverse-menu-complete", reversemenucomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX +"reverse-menu-complete", reversemenucomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP "run-help", processcmd, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL "self-insert", selfinsert, ZLE_MENUCMP | ZLE_KEEPSUFFIX "self-insert-unmeta", selfinsertunmeta, ZLE_MENUCMP | ZLE_KEEPSUFFIX diff --git a/Src/Zle/zle.h b/Src/Zle/zle.h index 71a929f87..f12505bd3 100644 --- a/Src/Zle/zle.h +++ b/Src/Zle/zle.h @@ -47,23 +47,29 @@ struct widget { ZleIntFunc fn; /* pointer to internally implemented widget */ char *fnnam; /* name of the shell function for user-defined widget */ Compctl cc; /* for use with a WIDGET_COMP widget */ + struct { + ZleIntFunc fn; /* internal widget function to call */ + char *wid; /* name of widget to call */ + char *func; /* name of shell function to call */ + } comp; } u; }; #define WIDGET_INT (1<<0) /* widget is internally implemented */ #define WIDGET_COMP (1<<1) /* Special completion widget */ -#define ZLE_MENUCMP (1<<2) /* DON'T invalidate completion list */ -#define ZLE_YANK (1<<3) -#define ZLE_LINEMOVE (1<<4) /* command is a line-oriented movement */ -#define ZLE_LASTCOL (1<<5) /* command maintains lastcol correctly */ -#define ZLE_KILL (1<<6) +#define WIDGET_NCOMP (1<<2) /* new style completion widget */ +#define ZLE_MENUCMP (1<<3) /* DON'T invalidate completion list */ +#define ZLE_YANK (1<<4) +#define ZLE_LINEMOVE (1<<5) /* command is a line-oriented movement */ +#define ZLE_LASTCOL (1<<6) /* command maintains lastcol correctly */ +#define ZLE_KILL (1<<7) #define ZLE_KEEPSUFFIX (1<<9) /* DON'T remove added suffix */ #define ZLE_USEMENU (1<<10) /* Do ) use menu completion for */ #define ZLE_NOMENU (1<<11) /* Don't ) widget, else use default */ #define ZLE_USEGLOB (1<<12) /* Do ) use glob completion for */ #define ZLE_NOGLOB (1<<13) /* Don't ) widget, else use default */ #define ZLE_NOTCOMMAND (1<<14) /* widget should not alter lastcmd */ - +#define ZLE_ISCOMP (1<<15) /* usable for new style completion */ /* thingies */ struct thingy { diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c index 7de96bd03..1ffe6f156 100644 --- a/Src/Zle/zle_keymap.c +++ b/Src/Zle/zle_keymap.c @@ -598,10 +598,10 @@ bin_bindkey(char *name, char **argv, char *ops, int func) int n; /* select operation and ensure no clashing arguments */ - for(op = opns; op->o && !ops[op->o]; op++) ; + for(op = opns; op->o && !ops[STOUC(op->o)]; op++) ; if(op->o) for(opp = op; (++opp)->o; ) - if(ops[opp->o]) { + if(ops[STOUC(opp->o)]) { zwarnnam(name, "incompatible operation selection options", NULL, 0); return 1; diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 515405a0d..2c0d3655e 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -443,9 +443,9 @@ zleread(char *lp, char *rp, int ha) insmode = unset(OVERSTRIKE); eofsent = 0; resetneeded = 0; - lpptbuf = promptexpand(lp, 1, NULL, NULL); + lpromptbuf = promptexpand(lp, 1, NULL, NULL); pmpt_attr = txtchange; - rpptbuf = promptexpand(rp, 1, NULL, NULL); + rpromptbuf = promptexpand(rp, 1, NULL, NULL); rpmpt_attr = txtchange; histallowed = ha; PERMALLOC { @@ -529,8 +529,8 @@ zleread(char *lp, char *rp, int ha) statusline = NULL; invalidatelist(); trashzle(); - free(lpptbuf); - free(rpptbuf); + free(lpromptbuf); + free(rpromptbuf); zleactive = 0; alarm(0); } LASTALLOC; @@ -565,13 +565,14 @@ execzlefunc(Thingy func) showmsg(msg); zsfree(msg); feep(); - } else if((w = func->widget)->flags & (WIDGET_INT|WIDGET_COMP)) { + } else if((w = func->widget)->flags & + (WIDGET_INT|WIDGET_COMP | WIDGET_NCOMP)) { int wflags = w->flags; if(!(wflags & ZLE_KEEPSUFFIX)) removesuffix(); if(!(wflags & ZLE_MENUCMP) || - ((wflags & WIDGET_COMP) && compwidget != w)) { + ((wflags & (WIDGET_COMP|WIDGET_NCOMP)) && compwidget != w)) { /* If we are doing a special completion, and the widget * is not the one currently in use for special completion, * we are starting a new completion. @@ -586,6 +587,9 @@ execzlefunc(Thingy func) if (wflags & WIDGET_COMP) { compwidget = w; completespecial(); + } else if (wflags & WIDGET_NCOMP) { + compwidget = w; + completecall(); } else w->u.fn(); if (!(wflags & ZLE_NOTCOMMAND)) @@ -855,7 +859,7 @@ trashzle(void) static struct builtin bintab[] = { BUILTIN("bindkey", 0, bin_bindkey, 0, -1, 0, "evaMldDANmrsLR", NULL), BUILTIN("vared", 0, bin_vared, 1, 7, 0, NULL, NULL), - BUILTIN("zle", 0, bin_zle, 0, -1, 0, "lDANCLmMgG", NULL), + BUILTIN("zle", 0, bin_zle, 0, -1, 0, "lDANCLmMgGc", NULL), }; /**/ @@ -869,6 +873,11 @@ setup_zle(Module m) spaceinlineptr = spaceinline; zlereadptr = zleread; + addmatchesptr = addmatches; + comp_strptr = comp_str; + getcpatptr = getcpat; + makecomplistcallptr = makecomplistcall; + /* initialise the thingies */ init_thingies(); @@ -931,6 +940,11 @@ finish_zle(Module m) spaceinlineptr = noop_function_int; zlereadptr = fallback_zleread; + addmatchesptr = NULL; + comp_strptr = NULL; + getcpatptr = NULL; + makecomplistcallptr = NULL; + return 0; } diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c index 27e9f2071..c8d6c70a7 100644 --- a/Src/Zle/zle_refresh.c +++ b/Src/Zle/zle_refresh.c @@ -33,7 +33,7 @@ /* Expanded prompts */ /**/ -char *lpptbuf, *rpptbuf; +char *lpromptbuf, *rpromptbuf; /* Text attributes after displaying prompts */ @@ -77,17 +77,17 @@ int cost; /* Oct/Nov 94: some code savagely redesigned to fix several bugs - refreshline() & tc_rightcurs() majorly rewritten; zrefresh() fixed - I've put my fingers into just about every routine in here - - any queries about updates to mason@werple.net.au */ + any queries about updates to mason@primenet.com.au */ static char **nbuf = NULL, /* new video buffer line-by-line char array */ **obuf = NULL; /* old video buffer line-by-line char array */ static int more_start, /* more text before start of screen? */ more_end, /* more stuff after end of screen? */ - lppth, /* lines taken up by the prompt */ olnct, /* previous number of lines */ ovln, /* previous video cursor position line */ - pptw, rpw, /* prompt widths on screen */ - rppth, /* right prompt height */ + lpromptw, rpromptw, /* prompt widths on screen */ + lprompth, /* lines taken up by the prompt */ + rprompth, /* right prompt height */ vcs, vln, /* video cursor position column & line */ vmaxln, /* video maximum number of lines */ winw, winh, rwinh, /* window width & height */ @@ -100,7 +100,6 @@ resetvideo(void) int ln; static int lwinw = -1, lwinh = -1; /* last window width & height */ - genprompts(); winw = columns; /* terminal width */ if (termflags & TERM_SHORT) winh = 1; @@ -132,13 +131,16 @@ resetvideo(void) *obuf[ln] = '\0'; } - if (pptw) { - memset(nbuf[0], ' ', pptw); - memset(obuf[0], ' ', pptw); - nbuf[0][pptw] = obuf[0][pptw] = '\0'; + countprompt(lpromptbuf, &lpromptw, &lprompth); + countprompt(rpromptbuf, &rpromptw, &rprompth); + + if (lpromptw) { + memset(nbuf[0], ' ', lpromptw); + memset(obuf[0], ' ', lpromptw); + nbuf[0][lpromptw] = obuf[0][lpromptw] = '\0'; } - vcs = pptw; + vcs = lpromptw; olnct = nlnct = 0; if (showinglist > 0) showinglist = -2; @@ -280,21 +282,25 @@ zrefresh(void) tsetcap(TCSTANDOUTEND, 0); tsetcap(TCUNDERLINEEND, 0); - if (!clearflag) + if (!clearflag) { if (tccan(TCCLEAREOD)) tcout(TCCLEAREOD); else cleareol = 1; /* request: clear to end of line */ + } if (t0 > -1) olnct = t0; if (termflags & TERM_SHORT) vcs = 0; - else if (!clearflag && lpptbuf[0]) - zputs(lpptbuf, shout); + else if (!clearflag && lpromptbuf[0]) { + zputs(lpromptbuf, shout); + if (lpromptw == 0) + zputs("\n", shout); /* works with both hasam and !hasam */ + } if (clearflag) { zputc('\r', shout); vcs = 0; - moveto(0, pptw); + moveto(0, lpromptw); } fflush(shout); clearf = clearflag; @@ -326,7 +332,7 @@ zrefresh(void) if (!*nbuf) *nbuf = (char *)zalloc(winw + 2); - s = (unsigned char *)(nbuf[ln = 0] + pptw); + s = (unsigned char *)(nbuf[ln = 0] + lpromptw); t = line; sen = (unsigned char *)(*nbuf + winw); for (; t < line+ll; t++) { @@ -425,15 +431,16 @@ zrefresh(void) /* determine whether the right-prompt exists and can fit on the screen */ if (!more_start) - put_rpmpt = rppth == 1 && rpptbuf[0] && !strchr(rpptbuf, '\t') && - (int)strlen(nbuf[0]) + rpw < winw - 1; + put_rpmpt = rprompth == 1 && rpromptbuf[0] && + !strchr(rpromptbuf, '\t') && + (int)strlen(nbuf[0]) + rpromptw < winw - 1; else { /* insert >.... on first line if there is more text before start of screen */ - memset(nbuf[0], ' ', pptw); - t0 = winw - pptw; + memset(nbuf[0], ' ', lpromptw); + t0 = winw - lpromptw; t0 = t0 > 5 ? 5 : t0; - strncpy(nbuf[0] + pptw, ">....", t0); - memset(nbuf[0] + pptw + t0, ' ', winw - t0 - pptw); + strncpy(nbuf[0] + lpromptw, ">....", t0); + memset(nbuf[0] + lpromptw + t0, ' ', winw - t0 - lpromptw); nbuf[0][winw] = nbuf[0][winw + 1] = '\0'; } @@ -477,8 +484,8 @@ zrefresh(void) /* output the right-prompt if appropriate */ if (put_rpmpt && !ln && !oput_rpmpt) { - moveto(0, winw - 1 - rpw); - zputs(rpptbuf, shout); + moveto(0, winw - 1 - rpromptw); + zputs(rpromptbuf, shout); vcs = winw - 1; /* reset character attributes to that set by the main prompt */ txtchange = pmpt_attr; @@ -659,12 +666,12 @@ refreshline(int ln) /* 2c: if we're on the first line, start checking at the end of the prompt; we shouldn't be doing anything within the prompt */ - if (ln == 0 && pptw) { - i = pptw - ccs; + if (ln == 0 && lpromptw) { + i = lpromptw - ccs; j = strlen(ol); nl += i; ol += (i > j ? j : i); /* if ol is too short, point it to '\0' */ - ccs = pptw; + ccs = lpromptw; } /* 3: main display loop - write out the buffer using whatever tricks we can */ @@ -815,7 +822,7 @@ moveto(int ln, int cl) instead of TCDOWN */ while (ln > vln) { - if (vln < vmaxln - 1) + if (vln < vmaxln - 1) { if (ln > vmaxln - 1) { if (tc_downcurs(vmaxln - 1 - vln)) vcs = 0; @@ -826,6 +833,7 @@ moveto(int ln, int cl) vln = ln; continue; } + } zputc('\r', shout), vcs = 0; /* safety precaution */ while (ln > vln) { zputc('\n', shout); @@ -893,21 +901,23 @@ tc_rightcurs(int cl) /* otherwise _carefully_ write the contents of the video buffer. if we're anywhere in the prompt, goto the left column and write the whole - prompt out unless ztrlen(lpptbuf) == pptw : we can cheat then */ - if (vln == 0 && i < pptw) { - if (strlen(lpptbuf) == pptw) - fputs(lpptbuf + i, shout); - else if (tccan(TCRIGHT) && (tclen[TCRIGHT] * ct <= ztrlen(lpptbuf))) + prompt out unless ztrlen(lpromptbuf) == lpromptw : we can cheat then */ + if (vln == 0 && i < lpromptw) { + if (strlen(lpromptbuf) == lpromptw) + fputs(lpromptbuf + i, shout); + else if (tccan(TCRIGHT) && (tclen[TCRIGHT] * ct <= ztrlen(lpromptbuf))) /* it is cheaper to send TCRIGHT than reprint the whole prompt */ - for (ct = pptw - i; ct--; ) + for (ct = lpromptw - i; ct--; ) tcout(TCRIGHT); else { if (i != 0) zputc('\r', shout); - tc_upcurs(lppth - 1); - zputs(lpptbuf, shout); + tc_upcurs(lprompth - 1); + zputs(lpromptbuf, shout); + if (lpromptw == 0) + zputs("\n", shout); /* works with both hasam and !hasam */ } - i = pptw; + i = lpromptw; ct = cl - i; } @@ -969,7 +979,7 @@ redisplay(void) { moveto(0, 0); zputc('\r', shout); /* extra care */ - tc_upcurs(lppth - 1); + tc_upcurs(lprompth - 1); resetneeded = 1; clearflag = 0; } @@ -987,7 +997,7 @@ singlerefresh(void) nlnct = 1; /* generate the new line buffer completely */ - for (vsiz = 1 + pptw, t0 = 0; t0 != ll; t0++, vsiz++) + for (vsiz = 1 + lpromptw, t0 = 0; t0 != ll; t0++, vsiz++) if (line[t0] == '\t') vsiz = (vsiz | 7) + 1; else if (icntrl(line[t0])) @@ -1002,9 +1012,10 @@ singlerefresh(void) cs = 0; } - memcpy(vbuf, strchr(lpptbuf, 0) - pptw, pptw); /* only use last part of prompt */ - vbuf[pptw] = '\0'; - vp = vbuf + pptw; + /* only use last part of prompt */ + memcpy(vbuf, strchr(lpromptbuf, 0) - lpromptw, lpromptw); + vbuf[lpromptw] = '\0'; + vp = vbuf + lpromptw; for (t0 = 0; t0 != ll; t0++) { if (line[t0] == '\t') @@ -1104,13 +1115,3 @@ singmoveto(int pos) } } } - -/* recheck size of prompts */ - -/**/ -static void -genprompts(void) -{ - countprompt(lpptbuf, &pptw, &lppth); - countprompt(rpptbuf, &rpw, &rppth); -} diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c index 68329be65..2e21b5add 100644 --- a/Src/Zle/zle_thingy.c +++ b/Src/Zle/zle_thingy.c @@ -246,7 +246,10 @@ freewidget(Widget w) { if ((w->flags & WIDGET_COMP) && w->u.cc) freecompctl(w->u.cc); - else if(!(w->flags & WIDGET_INT)) + else if (w->flags & WIDGET_NCOMP) { + zsfree(w->u.comp.wid); + zsfree(w->u.comp.func); + } else if(!(w->flags & WIDGET_INT)) zsfree(w->u.fnnam); zfree(w, sizeof(*w)); } @@ -337,16 +340,17 @@ bin_zle(char *name, char **args, char *ops, int func) { 'A', bin_zle_link, 2, 2 }, { 'N', bin_zle_new, 1, 2 }, { 'C', bin_zle_compctl, 1, -1}, + { 'c', bin_zle_complete, 3, 3 }, { 0, bin_zle_call, 0, -1 }, }; struct opn const *op, *opp; int n; /* select operation and ensure no clashing arguments */ - for(op = opns; op->o && !ops[op->o]; op++) ; + for(op = opns; op->o && !ops[STOUC(op->o)]; op++) ; if(op->o) for(opp = op; (++opp)->o; ) - if(ops[opp->o]) { + if(ops[STOUC(opp->o)]) { zerrnam(name, "incompatible operation selection options", NULL, 0); return 1; @@ -395,6 +399,11 @@ scanlistwidgets(HashNode hn, int list) if (w->flags & WIDGET_COMP) { if (printcompctlptr && w->u.cc) printcompctlptr(NULL, w->u.cc, PRINT_LIST, 0); + } else if (w->flags & WIDGET_NCOMP) { + fputc(' ', stdout); + quotedzputs(w->u.comp.wid, stdout); + fputc(' ', stdout); + quotedzputs(w->u.comp.func, stdout); } else if(strcmp(t->nam, w->u.fnnam)) { fputc(' ', stdout); quotedzputs(w->u.fnnam, stdout); @@ -405,6 +414,11 @@ scanlistwidgets(HashNode hn, int list) fputs(" -C", stdout); if (printcompctlptr && w->u.cc) printcompctlptr(NULL, w->u.cc, PRINT_TYPE, 0); + } else if (w->flags & WIDGET_NCOMP) { + fputs(" -c ", stdout); + nicezputs(w->u.comp.wid, stdout); + fputc(' ', stdout); + nicezputs(w->u.comp.func, stdout); } else if(strcmp(t->nam, w->u.fnnam)) { fputs(" (", stdout); nicezputs(w->u.fnnam, stdout); @@ -504,13 +518,41 @@ bin_zle_compctl(char *name, char **args, char *ops, char func) return 0; } +/**/ +static int +bin_zle_complete(char *name, char **args, char *ops, char func) +{ + Thingy t; + Widget w, cw; + + t = rthingy(args[1]); + cw = t->widget; + unrefthingy(t); + if (!(cw->flags & ZLE_ISCOMP)) { + zerrnam(name, "invalid widget `%s'", args[1], 0); + return 1; + } + w = zalloc(sizeof(*w)); + w->flags = WIDGET_NCOMP|ZLE_MENUCMP|ZLE_KEEPSUFFIX; + w->first = NULL; + w->u.comp.fn = cw->u.fn; + w->u.comp.wid = ztrdup(args[1]); + w->u.comp.func = ztrdup(args[2]); + if (bindwidget(w, rthingy(args[0]))) { + freewidget(w); + zerrnam(name, "widget name `%s' is protected", args[0], 0); + return 1; + } + return 0; +} + /**/ static int bin_zle_call(char *name, char **args, char *ops, char func) { Thingy t; - if(!zleactive || incompctlfunc) { + if(!zleactive || incompctlfunc || incompfunc) { zerrnam(name, "widgets can only be called when ZLE is active", NULL, 0); return 1; diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c index 8c976449e..a958752ca 100644 --- a/Src/Zle/zle_tricky.c +++ b/Src/Zle/zle_tricky.c @@ -237,6 +237,15 @@ struct aminfo { static Aminfo ainfo, fainfo; +/* This contains the name of the function to call if this is for a new * + * style completion. */ + +static char *compfunc = NULL; + +/* The memory heap to use for new style completion generation. */ + +static Heap compheap; + /* Find out if we have to insert a tab (instead of trying to complete). */ /**/ @@ -272,6 +281,15 @@ completespecial(void) docomplete(compwidget->u.cc ? COMP_WIDGET : COMP_COMPLETE); } +/**/ +void +completecall(void) +{ + compfunc = compwidget->u.comp.func; + compwidget->u.comp.fn(); + compfunc = NULL; +} + /**/ void completeword(void) @@ -408,11 +426,15 @@ reversemenucomplete(void) void acceptandmenucomplete(void) { + int sl = suffixlen[' ']; + if (!menucmp) { feep(); return; } - cs = menuend + menuinsc; + cs = menupos + menulen + menuinsc; + if (sl) + backdel(sl); inststrlen(" ", 1, 1); menuinsc = menulen = 0; menupos = cs; @@ -439,6 +461,13 @@ static int lastambig; static char *cmdstr; +/* This hold the name of the variable we are working on. */ + +static char *varname; + +/* != 0 if we are in a subscript */ + +static int insubscr; /* Check if the given string is the name of a parameter and if this * * parameter is one worth expanding. */ @@ -614,16 +643,13 @@ docomplete(int lst) lst = COMP_EXPAND; else { int t0, n = 0; - char *fc; struct hashnode *hn; for (t0 = cmdnamtab->hsize - 1; t0 >= 0; t0--) for (hn = cmdnamtab->nodes[t0]; hn; hn = hn->next) { - if (strpfx(q, hn->nam) && (fc = findcmd(hn->nam))) { - zsfree(fc); + if (strpfx(q, hn->nam) && findcmd(hn->nam, 0)) n++; - } if (n == 2) break; } @@ -889,7 +915,7 @@ unmetafy_line(void) static char * get_comp_string(void) { - int t0, tt0, i, j, k, cp, rd, sl, ocs; + int t0, tt0, i, j, k, cp, rd, sl, ocs, ins, oins; char *s = NULL, *linptr, *tmp, *p, *tt = NULL; zsfree(brbeg); @@ -943,13 +969,16 @@ get_comp_string(void) linredir = inredir; zsfree(cmdstr); cmdstr = NULL; + zsfree(varname); + varname = NULL; + insubscr = 0; zleparse = 1; clwpos = -1; lexsave(); inpush(dupstrspace((char *) linptr), 0, NULL); strinbeg(); stophist = 2; - i = tt0 = cp = rd = 0; + i = tt0 = cp = rd = ins = oins = 0; /* This loop is possibly the wrong way to do this. It goes through * * the previously massaged command line using the lexer. It stores * @@ -963,8 +992,10 @@ get_comp_string(void) * this would be to pass the command line through the parser too, * * and get the arguments that way. Maybe in 3.1... */ do { - lincmd = incmdpos; - linredir = inredir; + lincmd = ((incmdpos && !ins) || (oins == 2 && i == 2) || + (ins == 3 && i == 1)); + linredir = (inredir && !ins); + oins = ins; /* Get the next token. */ ctxtlex(); if (tok == DINPAR) @@ -973,7 +1004,9 @@ get_comp_string(void) /* We reached the end. */ if (tok == ENDINPUT) break; - if (tok == BAR || tok == AMPER || + if ((ins && (tok == DO || tok == SEPER)) || + (ins == 2 && i == 2) || (ins == 3 && i == 3) || + tok == BAR || tok == AMPER || tok == BARAMP || tok == AMPERBANG || ((tok == DBAR || tok == DAMPER) && !incond)) { /* This is one of the things that separate commands. If we * @@ -982,11 +1015,13 @@ get_comp_string(void) if (tt) break; /* Otherwise reset the variables we are collecting data in. */ - i = tt0 = cp = rd = 0; + i = tt0 = cp = rd = ins = 0; } - if (lincmd && tok == STRING) { + if (lincmd && (tok == STRING || tok == FOR || tok == FOREACH || + tok == SELECT || tok == REPEAT || tok == CASE)) { /* The lexer says, this token is in command position, so * * store the token string (to find the right compctl). */ + ins = (tok == REPEAT ? 2 : (tok != STRING)); zsfree(cmdstr); cmdstr = ztrdup(tokstr); i = 0; @@ -1004,9 +1039,13 @@ get_comp_string(void) rd = linredir; if (inwhat == IN_NOTHING && incond) inwhat = IN_COND; - } + } else if (linredir) + continue; if (!tokstr) continue; + /* Hack to allow completion after `repeat n do'. */ + if (oins == 2 && !i && !strcmp(tokstr, "do")) + ins = 3; /* We need to store the token strings of all words (for some of * * the more complicated compctl -x things). They are stored in * * the clwords array. Make this array big enough. */ @@ -1069,10 +1108,16 @@ get_comp_string(void) /* We found a simple string. */ s = ztrdup(clwords[clwpos]); } else if (t0 == ENVSTRING) { + char sav; /* The cursor was inside a parameter assignment. */ for (s = tt; iident(*s); s++); + sav = *s; + *s = '\0'; + zsfree(varname); + varname = ztrdup(tt); + *s = sav; if (skipparens(Inbrack, Outbrack, &s) > 0 || s > tt + cs - wb) - s = NULL, inwhat = IN_MATH; + s = NULL, inwhat = IN_MATH, insubscr = 1; else if (*s == '=') { s++; wb += s - tt; @@ -1110,14 +1155,32 @@ get_comp_string(void) * foo[_ wrong (note no $). If we are in a subscript, treat it * * as being in math. */ if (inwhat != IN_MATH) { - int i = 0; + int i = 0, hn = 0; + char *nb = (*s == String ? s + 1 : NULL), *ne = NULL; + for (tt = s; ++tt < s + cs - wb;) - if (*tt == Inbrack) + if (*tt == String) { + hn = 0; + nb = tt + 1; + } else if (*tt == Inbrack) { i++; - else if (i && *tt == Outbrack) + if (nb && !hn) { + hn = 1; + ne = tt; + } + } else if (i && *tt == Outbrack) i--; - if (i) + if (i) { inwhat = IN_MATH; + insubscr = 1; + if (hn && nb && ne) { + char sav = *ne; + *ne = '\0'; + zsfree(varname); + varname = ztrdup(nb); + *ne = sav; + } + } } if (inwhat == IN_MATH) { /* In mathematical expression, we complete parameter names (even * @@ -2336,6 +2399,119 @@ instmatch(Cmatch m) return r; } +/**/ +void +addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, + char *suf, char *group, + int flags, int quote, int menu, int nosort, int alt, char **argv) +{ + char *s, *t; + int lpl, lsl, i; + Aminfo ai = (alt ? fainfo : ainfo); + Cmatch cm; + + if (menu && isset(AUTOMENU)) + usemenu = 1; + SWITCHHEAPS(compheap) { + HEAPALLOC { + if (ipre) + ipre = dupstring(ipre); + if (ppre) { + ppre = dupstring(ppre); + lpl = strlen(ppre); + } else + lpl = 0; + if (psuf) { + psuf = dupstring(psuf); + lsl = strlen(psuf); + } else + lsl = 0; + if (pre) + pre = dupstring(pre); + if (suf) + suf = dupstring(suf); + if (!prpre && (prpre = ppre)) { + singsub(&prpre); + untokenize(prpre); + } else + prpre = dupstring(prpre); + if (group) { + endcmgroup(NULL); + begcmgroup(group, nosort); + if (nosort) + mgroup->flags |= CGF_NOSORT; + } + if (ai->pprefix) { + if (pre) + ai->pprefix[pfxlen(ai->pprefix, pre)] = '\0'; + else + ai->pprefix[0] = '\0'; + } else + ai->pprefix = dupstring(pre ? pre : ""); + + for (; (s = *argv); argv++) { + if (ai->firstm) { + if ((i = pfxlen(ai->firstm->str, s)) < ai->prerest) + ai->prerest = i; + if ((i = sfxlen(ai->firstm->str, s)) < ai->suflen) + ai->suflen = i; + } + t = s; + if (ppre) + t = dyncat(ppre, t); + if (ipre && *ipre) { + ai->noipre = 0; + if (ai->icpl > lpl) + ai->icpl = lpl; + if (ai->icsl > lsl) + ai->icsl = lsl; + if (ai->iaprefix) + ai->iaprefix[pfxlen(ai->iaprefix, t)] = '\0'; + else + ai->iaprefix = dupstring(t); + if (ai->iprefix) { + if (strcmp(ipre, ai->iprefix)) + ai->iprefix = ""; + } else + ai->iprefix = dupstring(ipre); + + t = dyncat(ipre, t); + } else + ai->iprefix = ""; + if (ai->cpl > lpl) + ai->cpl = lpl; + if (ai->csl > lsl) + ai->csl = lsl; + if (ai->aprefix) + ai->aprefix[pfxlen(ai->aprefix, t)] = '\0'; + else + ai->aprefix = dupstring(t); + mnum++; + ai->count++; + + cm = (Cmatch) halloc(sizeof(struct cmatch)); + cm->ppre = ppre; + cm->psuf = psuf; + cm->prpre = prpre; + if (!quote) + s = quotename(s, NULL, NULL, NULL); + cm->str = dupstring(s); + cm->ipre = cm->ripre = ipre; + cm->pre = pre; + cm->suf = suf; + cm->flags = flags; + cm->brpl = brpl; + cm->brsl = brsl; + addlinknode((alt ? fmatches : matches), cm); + + if (expl) + expl->fcount++; + if (!ai->firstm) + ai->firstm = cm; + } + } LASTALLOC; + } SWITCHBACKHEAPS; +} /* This adds a match to the list of matches. The string to add is given * * in s, the type of match is given in the global variable addwhat and * @@ -2351,7 +2527,7 @@ addmatch(char *s, char *t) { int test = 0, sl = strlen(s), pl = rpl, cc = 0, isf = 0; int mpl = 0, msl = 0, bpl = brpl, bsl = brsl; - char *e = NULL, *tt, *te, *fc, *ms = NULL; + char *e = NULL, *tt, *te, *ms = NULL; Comp cp = patcomp; HashNode hn; Param pm; @@ -2377,6 +2553,8 @@ addmatch(char *s, char *t) hn = (HashNode) t; pm = (Param) t; + if (incompfunc) + s = dupstring(s); if (!addwhat) { test = 1; } else if (addwhat == -1 || addwhat == -5 || addwhat == -6 || @@ -2427,11 +2605,8 @@ addmatch(char *s, char *t) } } if (test) { - fc = NULL; - if (addwhat == -7 && !(fc = findcmd(s))) + if (addwhat == -7 && !findcmd(s, 0)) return; - if (fc) - zsfree(fc); isf = CMF_FILE; if (addwhat == CC_FILES || addwhat == -6 || @@ -2515,7 +2690,6 @@ addmatch(char *s, char *t) } if (!test) return; - if (!ms && !ispattern && ai->firstm) { if ((test = sl - pfxlen(ai->firstm->str, s)) < ai->prerest) ai->prerest = test; @@ -2602,8 +2776,13 @@ addmatch(char *s, char *t) cm->str = (ms ? ms : s); cm->ipre = (ipre && *ipre ? ipre : NULL); cm->ripre = (ripre && *ripre ? ripre : NULL); - cm->pre = curcc->prefix; - cm->suf = curcc->suffix; + if (incompfunc) { + cm->pre = dupstring(curcc->prefix); + cm->suf = dupstring(curcc->suffix); + } else { + cm->pre = curcc->prefix; + cm->suf = curcc->suffix; + } cm->flags = mflags | isf; cm->brpl = bpl; cm->brsl = bsl; @@ -2729,7 +2908,7 @@ maketildelist(void) /* This does the check for compctl -x `n' and `N' patterns. */ /**/ -static int +int getcpat(char *str, int cpatindex, char *cpat, int class) { char *s, *t, *p; @@ -2951,6 +3130,8 @@ docompletion(char *s, int lst, int incmd) else if (nmatches == 1) { /* Only one match. */ + while (!amatches->mcount) + amatches = amatches->next; do_single(amatches->matches[0]); invalidatelist(); } @@ -3051,7 +3232,98 @@ makecomplist(char *s, int incmd, int lst) ccused = newlinklist(); ccstack = newlinklist(); - makecomplistglobal(s, incmd, lst); + if (compfunc) { + List list; + int lv = lastval; + + if ((list = getshfunc(compfunc)) != &dummy_list) { + LinkList args = newlinklist(); + char **p, *tmp; + int aadd = 0, usea = 1; + + addlinknode(args, compfunc); + + zsfree(compcontext); + zsfree(compcommand); + compcommand = ""; + if (inwhat == IN_MATH) { + if (insubscr) { + compcontext = "subscript"; + compcommand = varname ? varname : ""; + } else + compcontext = "math"; + usea = 0; + } else if (lincmd) + compcontext = (insubscr ? "subscript" : "command"); + else if (linredir) + compcontext = "redirect"; + else + switch (inwhat) { + case IN_ENV: + compcontext = "value"; + compcommand = varname; + usea = 0; + break; + case IN_COND: + compcontext = "condition"; + break; + default: + if (cmdstr) { + compcontext = "argument"; + compcommand = cmdstr; + } else { + compcontext = "value"; + if (clwords[0]) + compcommand = clwords[0]; + } + aadd = 1; + } + compcontext = ztrdup(compcontext); + tmp = quotename(compcommand, NULL, NULL, NULL); + untokenize(tmp); + compcommand = ztrdup(tmp); + if (usea && (!aadd || clwords[0])) + for (p = clwords + aadd; *p; p++) { + tmp = dupstring(*p); + untokenize(tmp); + addlinknode(args, tmp); + } + zsfree(compprefix); + zsfree(compsuffix); + if (unset(COMPLETEINWORD)) { + tmp = quotename(s, NULL, NULL, NULL); + untokenize(tmp); + compprefix = ztrdup(tmp); + compsuffix = ztrdup(""); + } else { + char *ss = s + offs, sav; + + tmp = quotename(s, &ss, NULL, NULL); + sav = *ss; + *ss = '\0'; + untokenize(tmp); + compprefix = ztrdup(tmp); + *ss = sav; + untokenize(ss); + compsuffix = ztrdup(ss); + } + zsfree(compiprefix); + compiprefix = ztrdup(""); + compcurrent = (usea ? (clwpos + 1 - aadd) : 1); + compnmatches = mnum; + incompfunc = 1; + startparamscope(); + makecompparamsptr(); + NEWHEAPS(compheap) { + doshfunc(compfunc, list, args, 0, 1); + } OLDHEAPS; + endparamscope(); + lastcmd = 9; + incompfunc = 0; + } + lastval = lv; + } else + makecomplistglobal(s, incmd, lst); endcmgroup(NULL); @@ -3082,6 +3354,83 @@ makecomplist(char *s, int incmd, int lst) return 1; } +/* This should probably be moved into tokenize(). */ + +static char * +ctokenize(char *p) +{ + char *r = p; + int bslash = 0; + + tokenize(p); + + for (p = r; *p; p++) { + if (*p == '\\') + bslash = 1; + else { + if (*p == '$') { + if (bslash) + p[-1] = Bnull; + else + *p = String; + } + bslash = 0; + } + } + return r; +} + +/**/ +char * +comp_str(int *ipl, int *pl) +{ + char *p = dupstring(compprefix); + char *s = dupstring(compsuffix); + char *ip = dupstring(compiprefix); + char *str; + int lp, ls, lip; + + ctokenize(p); + remnulargs(p); + ctokenize(s); + remnulargs(s); + ctokenize(ip); + remnulargs(ip); + ls = strlen(s); + lip = strlen(ip); + lp = strlen(p); + str = halloc(lip + lp + ls + 1); + strcpy(str, ip); + strcat(str, p); + strcat(str, s); + + if (ipl) + *ipl = lip; + if (pl) + *pl = lp; + + return str; +} + +/**/ +void +makecomplistcall(Compctl cc) +{ + SWITCHHEAPS(compheap) { + HEAPALLOC { + int ooffs = offs, lip, lp; + char *str = comp_str(&lip, &lp); + + offs = lip + lp; + cc->refc++; + ccont = 0; + makecomplistor(cc, str, lincmd, lip, 0); + offs = ooffs; + compnmatches = mnum; + } LASTALLOC; + } SWITCHBACKHEAPS; +} + /* This function gets the compctls for the given command line and * * adds all completions for them. */ @@ -3159,7 +3508,7 @@ makecomplistcmd(char *os, int incmd) /* If the command string starts with `=', try the path name of the * * command. */ if (cmdstr && cmdstr[0] == Equals) { - char *c = findcmd(cmdstr + 1); + char *c = findcmd(cmdstr + 1, 1); if (c) { zsfree(cmdstr); @@ -3191,7 +3540,7 @@ makecomplistpc(char *os, int incmd) { Patcomp pc; Comp pat; - char *s = findcmd(cmdstr); + char *s = findcmd(cmdstr, 1); for (pc = patcomps; pc; pc = pc->next) { if ((pat = parsereg(pc->pat)) && @@ -3468,12 +3817,12 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) ccont |= (cc->mask2 & (CC_CCCONT | CC_DEFCONT | CC_PATCONT)); - if (findnode(ccstack, cc)) + if (!incompfunc && findnode(ccstack, cc)) return; addlinknode(ccstack, cc); - if (allccs) { + if (!incompfunc && allccs) { if (findnode(allccs, cc)) { uremnode(ccstack, firstnode(ccstack)); return; @@ -4107,7 +4456,8 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) } /* This flag allows us to use read -l and -c. */ - incompctlfunc = 1; + if (!incompfunc) + incompctlfunc = 1; sfcontext = SFC_COMPLETE; /* Call the function. */ doshfunc(cc->func, list, args, 0, 1); @@ -4126,7 +4476,8 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) char *j, *jj; for (i = 0; i < MAXJOB; i++) - if (jobtab[i].stat & STAT_INUSE) { + if ((jobtab[i].stat & STAT_INUSE) && + jobtab[i].procs && jobtab[i].procs->text) { int stopped = jobtab[i].stat & STAT_STOPPED; j = jj = dupstring(jobtab[i].procs->text); @@ -4274,7 +4625,8 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) } /* No harm in allowing read -l and -c here, too */ - incompctlfunc = 1; + if (!incompfunc) + incompctlfunc = 1; sfcontext = SFC_COMPLETE; doshfunc(cc->ylist, list, args, 0, 1); sfcontext = osc; @@ -4528,10 +4880,12 @@ makearray(LinkList l, int s, int *np, int *nlp) for (bp = ap; bp[1] && matcheq(*ap, bp[1]); bp++, n--); ap = bp; /* Mark those, that would show the same string in the list. */ - for (; bp[1] && !strcmp((*ap)->str, (bp[1])->str); bp++) { - (bp[1])->flags |= CMF_NOLIST; nl++; - } + for (; bp[1] && !strcmp((*ap)->str, (bp[1])->str); bp++) + (bp[1])->flags |= CMF_NOLIST; } + for (ap = rp; *ap; ap++) + if ((*ap)->flags & CMF_NOLIST) + nl++; *cp = NULL; } if (np) @@ -4991,10 +5345,14 @@ do_single(Cmatch m) if (m->suf) { havesuff = 1; menuinsc = ztrlen(m->suf); - if (menuwe && (m->flags & CMF_REMOVE)) { - makesuffix(menuinsc); - if (menuinsc == 1) - suffixlen[m->suf[0]] = 1; + menulen -= menuinsc; + if (menuwe) { + menuend += menuinsc; + if (m->flags & CMF_REMOVE) { + makesuffix(menuinsc); + if (menuinsc == 1) + suffixlen[STOUC(m->suf[0])] = 1; + } } } else { /* There is no user-specified suffix, * @@ -5463,7 +5821,8 @@ listmatches(void) } if (n) { putc('\n', shout); - p = skipnolist(p + 1); + if (n && nl) + p = skipnolist(p + 1); } } } @@ -5671,7 +6030,7 @@ expandcmdpath(void) feep(); return; } - str = findcmd(s); + str = findcmd(s, 1); zsfree(s); if (!str) { feep(); @@ -5686,7 +6045,6 @@ expandcmdpath(void) cs += cmdwe - cmdwb + strlen(str); if (cs > ll) cs = ll; - zsfree(str); } /* Extra function added by AR Iano-Fletcher. */ -- cgit 1.4.1