diff options
Diffstat (limited to 'Src/Zle')
-rw-r--r-- | Src/Zle/comp.h | 7 | ||||
-rw-r--r-- | Src/Zle/comp1.c | 5 | ||||
-rw-r--r-- | Src/Zle/compctl.c | 12 | ||||
-rw-r--r-- | Src/Zle/zle_thingy.c | 11 | ||||
-rw-r--r-- | Src/Zle/zle_tricky.c | 953 |
5 files changed, 586 insertions, 402 deletions
diff --git a/Src/Zle/comp.h b/Src/Zle/comp.h index 0d5419817..76ac67114 100644 --- a/Src/Zle/comp.h +++ b/Src/Zle/comp.h @@ -271,9 +271,10 @@ struct cline { #define CLF_MISS 4 #define CLF_DIFF 8 #define CLF_SUF 16 -#define CLF_NEW 32 -#define CLF_VAR 64 -#define CLF_JOIN 128 +#define CLF_PNEW 32 +#define CLF_SNEW 64 +#define CLF_VAR 128 +#define CLF_JOIN 256 /* Flags for makecomplist*(). Things not to do. */ diff --git a/Src/Zle/comp1.c b/Src/Zle/comp1.c index 77fe0a1fe..72f3cea53 100644 --- a/Src/Zle/comp1.c +++ b/Src/Zle/comp1.c @@ -49,10 +49,10 @@ void (*makecompparamsptr) _((void)); /* pointers to functions required by compctl and defined by zle */ /**/ -void (*addmatchesptr) _((char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, int, int, Cmatcher, char **)); +void (*addmatchesptr) _((char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, int, int, Cmatcher, char *, char **)); /**/ -char *(*comp_strptr) _((int*,int*)); +char *(*comp_strptr) _((int*, int*, int)); /**/ int (*getcpatptr) _((char *, int, char *, int)); @@ -410,6 +410,7 @@ setup_comp1(Module m) cc_first.mask2 = CC_CCCONT; compcontext = compcommand = compprefix = compsuffix = compiprefix = NULL; + makecompparamsptr = NULL; return 0; } diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c index e3b778508..f71d67510 100644 --- a/Src/Zle/compctl.c +++ b/Src/Zle/compctl.c @@ -1676,7 +1676,7 @@ 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, *m = NULL, *rs = NULL; - char *ign = NULL, *rf = NULL; + char *ign = NULL, *rf = NULL, *expl = NULL; int f = 0, a = 0, dm; Cmatcher match = NULL; @@ -1757,6 +1757,10 @@ bin_compadd(char *name, char **argv, char *ops, int func) e = "matching specification expected after -%c"; dm = 1; break; + case 'X': + sp = &expl; + e = "string expected after -%c"; + break; case 'r': f |= CMF_REMOVE; sp = &rs; @@ -1802,7 +1806,7 @@ bin_compadd(char *name, char **argv, char *ops, int func) match = cpcmatcher(match); addmatchesptr(ipre, ppre, psuf, prpre, pre, suf, group, - rs, rf, ign, f, a, match, argv); + rs, rf, ign, f, a, match, expl, argv); freecmatcher(match); return 0; @@ -2049,8 +2053,8 @@ cond_strcl(char **a, int id) zerr("zle not loaded, zle condition not available", NULL, 0); return 1; } - i = getcpatptr(comp_strptr(&ipl, NULL), i, s, id); - if (i != -1) { + i = getcpatptr(comp_strptr(&ipl, NULL, 1), i, s, id); + if (i != -1 && i >= ipl) { ignore_prefix(i - ipl); return 1; } diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c index d055c45c1..28781e7f0 100644 --- a/Src/Zle/zle_thingy.c +++ b/Src/Zle/zle_thingy.c @@ -478,6 +478,17 @@ bin_zle_complete(char *name, char **args, char *ops, char func) Thingy t; Widget w, cw; +#ifdef DYNAMIC + if (!require_module(name, "compctl", 0, 0)) { + zerrnam(name, "can't load compctl module", NULL, 0); + return 1; + } +#else + if (!makecompparamsptr) { + zerrnam(name, "compctl module not available", NULL, 0); + return 1; + } +#endif t = rthingy(args[1]); cw = t->widget; unrefthingy(t); diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c index af78e1c06..4b42640e1 100644 --- a/Src/Zle/zle_tricky.c +++ b/Src/Zle/zle_tricky.c @@ -214,11 +214,9 @@ static Cmlist mstack; /* The completion matchers used when building new stuff for the line. */ -static struct cmlist bmstack0, bmstack1; -static Cmlist bmstack; -static int had_lm; +static Cmlist bmatchers; -/* A list with references to all matcher we used. */ +/* A list with references to all matchers we used. */ static LinkList matchers; @@ -293,12 +291,24 @@ enum { COMP_COMPLETE, static int lastambig; -/* Non-zero if the string on the line came from a previous completion. * - * This is used to detect if the string should be taken as an exact * - * match (see do_ambiguous()). */ +/* This says what of the state the line is in when completion is started * + * came from a previous completion. If the FC_LINE bit is set, the * + * string was inserted. If FC_INWORD is set, the last completion moved * + * the cursor into the word although it was at the end of it when the * + * last completion was invoked. * + * This is used to detect if the string should be taken as an exact * + * match (see do_ambiguous()) and if the cursor has to be moved to the * + * end of the word before generating the completions. */ static int fromcomp; +/* This holds the end-position of the last string inserted into the line. */ + +static int lastend; + +#define FC_LINE 1 +#define FC_INWORD 2 + /**/ void completecall(void) @@ -607,6 +617,12 @@ docomplete(int lst) return; } + /* We may have to reset the cursor to its position after the * + * string inserted by the last completion. */ + + if (fromcomp & FC_INWORD) + cs = lastend; + /* Check if we have to start a menu-completion (via automenu). */ if ((amenu = (isset(AUTOMENU) && lastambig && @@ -1567,6 +1583,83 @@ addtocline(Cline *retp, Cline *lrp, *lrp = ln; } +/* This compares two cpattern lists and returns non-zero if they are + * equal. */ + +static int +cmp_cpatterns(Cpattern a, Cpattern b) +{ + while (a) { + if (a->equiv != b->equiv || memcmp(a->tab, b->tab, 256)) + return 0; + a = a->next; + b = b->next; + } + return 1; +} + +/* This compares two cmatchers and returns non-zero if they are equal. */ + +static int +cmp_cmatchers(Cmatcher a, Cmatcher b) +{ + return (a == b || + (a->flags == b->flags && + a->llen == b->llen && a->wlen == b->wlen && + (!a->llen || cmp_cpatterns(a->line, b->line)) && + (a->wlen <= 0 || cmp_cpatterns(a->word, b->word)) && + (!(a->flags & CMF_LEFT) || + (a->lalen == b->lalen && + (!a->lalen || cmp_cpatterns(a->left, b->left)))) && + (!(a->flags & CMF_RIGHT) || + (a->ralen == b->ralen && + (!a->ralen || cmp_cpatterns(a->right, b->right)))))); +} + +/* Add the given matchers to the bmatcher list. */ + +static void +add_bmatchers(Cmatcher m) +{ + Cmlist old = bmatchers, *q = &bmatchers, n; + + for (; m; m = m->next) { + if ((!m->flags && m->wlen > 0 && m->llen > 0) || + (m->flags == CMF_RIGHT && m->wlen == -1 && !m->llen)) { + *q = n = (Cmlist) halloc(sizeof(struct cmlist)); + n->matcher = m; + q = &(n->next); + } + } + *q = old; +} + +/* This is called when the matchers in the mstack have changed to + * ensure that the bmatchers list contains no matchers not in mstack. */ + +static void +update_bmatchers(void) +{ + Cmlist p = bmatchers, q = NULL, ms; + Cmatcher mp; + int t; + + while (p) { + t = 0; + for (ms = mstack; ms && !t; ms = ms->next) + for (mp = ms->matcher; mp && !t; mp = mp->next) + t = cmp_cmatchers(mp, p->matcher); + + p = p->next; + if (!t) { + if (q) + q->next = p; + else + bmatchers = p; + } + } +} + /* When building up cline lists that are to be inserted at the end of the * string or on the left hand side in the middle, we do this separately for * multiple runs of characters separated by the anchors of `*' match patterns. @@ -1582,21 +1675,20 @@ end_list(int len, char *str) char *p = str; while (len) { - for (t = 0, ms = bmstack; ms && !t; ms = ms->next) { - for (mp = ms->matcher; mp && !t; mp = mp->next) { - if (mp->flags == CMF_RIGHT && mp->wlen == -1 && - !mp->llen && len >= mp->ralen && mp->ralen && - pattern_match(mp->right, str, NULL, NULL)) { - /* This is one of those patterns, so add a cline struct. - * We store the anchor string in the line and the contents - * (i.e. the strings between the anchors) in the word field. */ - *q = getcline(str, mp->ralen, p, str - p, 0); - q = &((*q)->next); - str += mp->ralen; - len -= mp->ralen; - p = str; - t = 1; - } + for (t = 0, ms = bmatchers; ms && !t; ms = ms->next) { + mp = ms->matcher; + if (mp->flags == CMF_RIGHT && mp->wlen == -1 && + !mp->llen && len >= mp->ralen && mp->ralen && + pattern_match(mp->right, str, NULL, NULL)) { + /* This is one of those patterns, so add a cline struct. + * We store the anchor string in the line and the contents + * (i.e. the strings between the anchors) in the word field. */ + *q = getcline(str, mp->ralen, p, str - p, 0); + q = &((*q)->next); + str += mp->ralen; + len -= mp->ralen; + p = str; + t = 1; } } if (!t) { @@ -1616,7 +1708,7 @@ end_list(int len, char *str) /* This builds a string that may be put on the line that fully matches the * given strings. The return value is NULL if no such string could be built - * or that string, allocated on the heap. + * or that string in local static memory, dup it. * All this is a lot like the procedure in bld_new_pfx(), only slightly * simpler, see that function for more comments. */ @@ -1644,60 +1736,59 @@ join_strs(int la, char *sa, int lb, char *sb) } while (la && lb) { if (*sa != *sb) { - for (t = 0, ms = bmstack; ms && !t; ms = ms->next) { - for (mp = ms->matcher; mp && !t; mp = mp->next) { - if (!mp->flags && mp->wlen > 0 && mp->llen > 0 && - mp->wlen <= la && mp->wlen <= lb) { - if (pattern_match(mp->word, sa, NULL, ea)) { - if (mp->llen + 1 > llen) { - if (llen) - zfree(line, llen); - line = (char *) zalloc(llen = mp->llen + 20); - } - if ((bl = bld_line_pfx(mp->line, line, line, - lb, sb, ea))) { - line[mp->llen] = '\0'; - if (rr <= mp->llen) { - char *or = rs; - - rs = realloc(rs, (rl += 20)); - rr += 20; - rp += rs - or; - } - memcpy(rp, line, mp->llen); - rp += mp->llen; - rr -= mp->llen; - sa += mp->wlen; - sb += bl; - la -= mp->wlen; - lb -= bl; - t = 1; - } - } else if (pattern_match(mp->word, sb, NULL, ea)) { - if (mp->llen + 1 > llen) { - if (llen) - zfree(line, llen); - line = (char *) zalloc(llen = mp->llen + 20); + for (t = 0, ms = bmatchers; ms && !t; ms = ms->next) { + mp = ms->matcher; + if (!mp->flags && mp->wlen > 0 && mp->llen > 0 && + mp->wlen <= la && mp->wlen <= lb) { + if (pattern_match(mp->word, sa, NULL, ea)) { + if (mp->llen + 1 > llen) { + if (llen) + zfree(line, llen); + line = (char *) zalloc(llen = mp->llen + 20); + } + if ((bl = bld_line_pfx(mp->line, line, line, + lb, sb, ea))) { + line[mp->llen] = '\0'; + if (rr <= mp->llen) { + char *or = rs; + + rs = realloc(rs, (rl += 20)); + rr += 20; + rp += rs - or; } - if ((bl = bld_line_pfx(mp->line, line, line, - la, sa, ea))) { - line[mp->llen] = '\0'; - if (rr <= mp->llen) { - char *or = rs; - - rs = realloc(rs, (rl += 20)); - rr += 20; - rp += rs - or; - } - memcpy(rp, line, mp->llen); - rp += mp->llen; - rr -= mp->llen; - sa += bl; - sb += mp->wlen; - la -= bl; - lb -= mp->wlen; - t = 1; + memcpy(rp, line, mp->llen); + rp += mp->llen; + rr -= mp->llen; + sa += mp->wlen; + sb += bl; + la -= mp->wlen; + lb -= bl; + t = 1; + } + } else if (pattern_match(mp->word, sb, NULL, ea)) { + if (mp->llen + 1 > llen) { + if (llen) + zfree(line, llen); + line = (char *) zalloc(llen = mp->llen + 20); + } + if ((bl = bld_line_pfx(mp->line, line, line, + la, sa, ea))) { + line[mp->llen] = '\0'; + if (rr <= mp->llen) { + char *or = rs; + + rs = realloc(rs, (rl += 20)); + rr += 20; + rp += rs - or; } + memcpy(rp, line, mp->llen); + rp += mp->llen; + rr -= mp->llen; + sa += bl; + sb += mp->wlen; + la -= bl; + lb -= mp->wlen; + t = 1; } } } @@ -1725,7 +1816,7 @@ join_strs(int la, char *sa, int lb, char *sb) *rp = '\0'; - return dupstring(rs); + return rs; } /* This gets two cline lists with separated runs and joins the corresponding @@ -1752,26 +1843,55 @@ join_ends(Cline o, Cline n, int *olp, int *nlp) * and mark the cline so that we don't try to join it again. */ o->flags |= CLF_JOIN; o->llen = strlen(j); - o->line = j; + o->line = dupstring(j); bld_pfx(o, n, &mol, &mnl); smol += mol + o->llen; smnl += mnl + n->llen; } else { - /* Different anchor strings, so shorten the list. */ + /* Different anchors, see if we can find matching anchors + * further down the lists. */ + Cline to, tn; + int t = 0; + + /* But first build the common prefix. */ bld_pfx(o, n, &mol, &mnl); smol += mol; smnl += mnl; - o->flags |= CLF_MISS; - o->next = NULL; - o->llen = 0; - if (olp) - *olp = smol; - if (nlp) - *nlp = smnl; - return ret; + + for (to = o; to && !t; to = to->next) { + for (tn = n; tn && !t; tn = tn->next) { + if ((t = ((to->llen == tn->llen && + !strncmp(to->line, tn->line, to->llen)) || + (!(to->flags & CLF_JOIN) && + join_strs(to->llen, to->line, + tn->llen, tn->line))))) + break; + } + if (t) + break; + } + if (t) { + /* Found matching anchors, continue with them. */ + o->line = to->line; + o->llen = to->llen; + o->next = to->next; + o->flags |= CLF_MISS; + n = tn; + } else { + /* No matching anchors found, shorten the list. */ + o->flags |= CLF_MISS; + o->next = NULL; + o->llen = 0; + if (olp) + *olp = smol; + if (nlp) + *nlp = smnl; + return ret; + } } /* If we reached the end of the new list but not the end of the old - * list, we mark the old list (saying that characters are missing here). */ + * list, we mark the old list (saying that characters are missing + * here). */ if (!(n = n->next) && o->next) o->flags |= CLF_MISS; o = o->next; @@ -1859,20 +1979,19 @@ bld_line_pfx(Cpattern pat, char *line, char *lp, rl++; } else { t = 0; - for (ms = bmstack; ms && !t; ms = ms->next) { - for (mp = ms->matcher; mp && !t; mp = mp->next) { - if (!mp->flags && mp->wlen <= wlen && mp->llen <= l && - pattern_match(mp->line, line, NULL, ea) && - pattern_match(mp->word, word, ea, NULL)) { - /* Both the line and the word pattern matched, - * now skip over the matched portions. */ - line += mp->llen; - word += mp->wlen; - l -= mp->llen; - wlen -= mp->wlen; - rl += mp->wlen; - t = 1; - } + for (ms = bmatchers; ms && !t; ms = ms->next) { + mp = ms->matcher; + if (!mp->flags && mp->wlen <= wlen && mp->llen <= l && + pattern_match(mp->line, line, NULL, ea) && + pattern_match(mp->word, word, ea, NULL)) { + /* Both the line and the word pattern matched, + * now skip over the matched portions. */ + line += mp->llen; + word += mp->wlen; + l -= mp->llen; + wlen -= mp->wlen; + rl += mp->wlen; + t = 1; } } if (!t) @@ -1923,100 +2042,99 @@ bld_new_pfx(int ol, char *ow, int nl, char *nw, int *olp, int *nlp, Cline *lp) while (ol && nl) { if (*ow != *nw) { /* Not the same character, use the patterns. */ - for (t = 0, ms = bmstack; ms && !t; ms = ms->next) { - for (mp = ms->matcher; mp && !t; mp = mp->next) { - /* We use only those patterns that match a non-empty - * string in both the line and the word, that match - * strings no longer than the string we still have - * to compare, that don't have anchors, and that don't - * use the line strings for insertion. */ - if (!mp->flags && mp->wlen > 0 && mp->llen > 0 && - mp->wlen <= ol && mp->wlen <= nl) { - /* Try the pattern only if the word-pattern matches - * one of the strings. */ - if (pattern_match(mp->word, ow, NULL, ea)) { - /* Make the buffer where we build the possible - * line patterns big enough. */ - if (mp->llen + 1 > llen) { - if (llen) - zfree(line, llen); - line = (char *) zalloc(llen = mp->llen + 20); - } - /* Then build all the possible lines and see - * if one of them matches the othe string. */ - if ((bl = bld_line_pfx(mp->line, line, line, - nl, nw, ea))) { - /* Yep, one of the lines matched the other - * string. */ - if (p != ow) { - /* There is still a substring that is - * the same in both strings, so add - * a cline for it. */ - char sav = *ow; - - *ow = '\0'; - n = getcline(NULL, 0, dupstring(p), - ow - p, 0); - *ow = sav; - if (l) - l->next = n; - else - ret = n; - l = n; - } - /* Then we add the line string built. */ - line[mp->llen] = '\0'; - n = getcline(dupstring(line), mp->llen, - NULL, 0, CLF_DIFF); + for (t = 0, ms = bmatchers; ms && !t; ms = ms->next) { + mp = ms->matcher; + /* We use only those patterns that match a non-empty + * string in both the line and the word, that match + * strings no longer than the string we still have + * to compare, that don't have anchors, and that don't + * use the line strings for insertion. */ + if (!mp->flags && mp->wlen > 0 && mp->llen > 0 && + mp->wlen <= ol && mp->wlen <= nl) { + /* Try the pattern only if the word-pattern matches + * one of the strings. */ + if (pattern_match(mp->word, ow, NULL, ea)) { + /* Make the buffer where we build the possible + * line patterns big enough. */ + if (mp->llen + 1 > llen) { + if (llen) + zfree(line, llen); + line = (char *) zalloc(llen = mp->llen + 20); + } + /* Then build all the possible lines and see + * if one of them matches the othe string. */ + if ((bl = bld_line_pfx(mp->line, line, line, + nl, nw, ea))) { + /* Yep, one of the lines matched the other + * string. */ + if (p != ow) { + /* There is still a substring that is + * the same in both strings, so add + * a cline for it. */ + char sav = *ow; + + *ow = '\0'; + n = getcline(NULL, 0, dupstring(p), + ow - p, 0); + *ow = sav; if (l) l->next = n; else ret = n; l = n; - ow += mp->wlen; - nw += bl; - ol -= mp->wlen; - nl -= bl; - p = ow; - t = 1; - } - } else if (pattern_match(mp->word, nw, NULL, ea)) { - /* Now do the same for the other string. */ - if (mp->llen + 1 > llen) { - if (llen) - zfree(line, llen); - line = (char *) zalloc(llen = mp->llen + 20); } - if ((bl = bld_line_pfx(mp->line, line, line, - ol, ow, ea))) { - if (p != ow) { - char sav = *ow; - - *ow = '\0'; - n = getcline(NULL, 0, dupstring(p), - ow - p, 0); - *ow = sav; - if (l) - l->next = n; - else - ret = n; - l = n; - } - line[mp->llen] = '\0'; - n = getcline(dupstring(line), mp->llen, - NULL, 0, CLF_DIFF); + /* Then we add the line string built. */ + line[mp->llen] = '\0'; + n = getcline(dupstring(line), mp->llen, + NULL, 0, CLF_DIFF); + if (l) + l->next = n; + else + ret = n; + l = n; + ow += mp->wlen; + nw += bl; + ol -= mp->wlen; + nl -= bl; + p = ow; + t = 1; + } + } else if (pattern_match(mp->word, nw, NULL, ea)) { + /* Now do the same for the other string. */ + if (mp->llen + 1 > llen) { + if (llen) + zfree(line, llen); + line = (char *) zalloc(llen = mp->llen + 20); + } + if ((bl = bld_line_pfx(mp->line, line, line, + ol, ow, ea))) { + if (p != ow) { + char sav = *ow; + + *ow = '\0'; + n = getcline(NULL, 0, dupstring(p), + ow - p, 0); + *ow = sav; if (l) l->next = n; else ret = n; l = n; - ow += bl; - nw += mp->wlen; - ol -= bl; - nl -= mp->wlen; - p = ow; - t = 1; } + line[mp->llen] = '\0'; + n = getcline(dupstring(line), mp->llen, + NULL, 0, CLF_DIFF); + if (l) + l->next = n; + else + ret = n; + l = n; + ow += bl; + nw += mp->wlen; + ol -= bl; + nl -= mp->wlen; + p = ow; + t = 1; } } } @@ -2107,19 +2225,18 @@ join_new_pfx(Cline line, int len, char *word, int *missp) ll--; len--; } else { - for (t = 0, ms = bmstack; ms && !t; ms = ms->next) { - for (mp = ms->matcher; mp && !t; mp = mp->next) { - if (!mp->flags && mp->wlen > 0 && mp->llen > 0 && - mp->wlen <= len && mp->llen <= len && - pattern_match(mp->word, word, NULL, ea) && - pattern_match(mp->line, p, ea, NULL)) { - /* We have a matched substring, skip over. */ - p += mp->llen; - word += mp->wlen; - ll -= mp->llen; - len -= mp->wlen; - t = 1; - } + for (t = 0, ms = bmatchers; ms && !t; ms = ms->next) { + mp = ms->matcher; + if (!mp->flags && mp->wlen > 0 && mp->llen > 0 && + mp->wlen <= len && mp->llen <= len && + pattern_match(mp->word, word, NULL, ea) && + pattern_match(mp->line, p, ea, NULL)) { + /* We have a matched substring, skip over. */ + p += mp->llen; + word += mp->wlen; + ll -= mp->llen; + len -= mp->wlen; + t = 1; } } if (!t) @@ -2148,6 +2265,7 @@ join_new_pfx(Cline line, int len, char *word, int *missp) l->next = line; else ret = line; + l = line; } } else { /* The cline doesn't have a string built by reverse matching, @@ -2163,6 +2281,7 @@ join_new_pfx(Cline line, int len, char *word, int *missp) l->next = line; else ret = line; + l = line; len = 0; } else { char sav = word[len]; @@ -2180,6 +2299,7 @@ join_new_pfx(Cline line, int len, char *word, int *missp) l->next = line; else ret = line; + l = line; len = 0; } else if (strpfx(line->word, word)) { word[len] = sav; @@ -2190,6 +2310,7 @@ join_new_pfx(Cline line, int len, char *word, int *missp) l->next = line; else ret = line; + l = line; len = 0; } else { /* Not the same and no prefix, so we try to build a @@ -2208,6 +2329,7 @@ join_new_pfx(Cline line, int len, char *word, int *missp) l->next = sl; else ret = sl; + l = sl; if (!mol) { send->next = next; word += len - mnl; @@ -2238,7 +2360,11 @@ join_new_pfx(Cline line, int len, char *word, int *missp) static void bld_pfx(Cline o, Cline n, int *olp, int *nlp) { - if (o->flags & CLF_NEW) { + if (olp) + *olp = 0; + if (nlp) + *nlp = 0; + if (o->flags & CLF_PNEW) { if (o->flags & (CLF_END | CLF_MID)) /* We split the suffix in the middle and at the end into * separate runs. */ @@ -2255,7 +2381,7 @@ bld_pfx(Cline o, Cline n, int *olp, int *nlp) o->flags |= CLF_MISS; } } else if (o->flags & (CLF_END | CLF_MID)) { - o->flags |= CLF_NEW; + o->flags |= CLF_PNEW; o->prefix = join_ends(end_list(o->wlen, o->word), end_list(n->wlen, n->word), olp, nlp); } else if (o->wlen && n->wlen) { @@ -2280,7 +2406,7 @@ bld_pfx(Cline o, Cline n, int *olp, int *nlp) * matches both strings from the original cline structs * and thus can be put in the command line to represent * them. This cline list is stored in o. */ - o->flags |= CLF_NEW; + o->flags |= CLF_PNEW; o->prefix = bld_new_pfx(o->wlen, o->word, n->wlen, n->word, &mol, &mnl, NULL); newl = 0; @@ -2300,7 +2426,8 @@ bld_pfx(Cline o, Cline n, int *olp, int *nlp) if (!o->prefix && n->wlen != o->wlen) o->flags |= CLF_MISS; - } + } else + o->wlen = 0; } /* The following function are like their counterparts above, only for @@ -2353,20 +2480,19 @@ bld_line_sfx(Cpattern pat, char *line, char *lp, rl++; } else { t = 0; - for (ms = bmstack; ms && !t; ms = ms->next) { - for (mp = ms->matcher; mp && !t; mp = mp->next) { - if (!mp->flags && mp->wlen <= wlen && mp->llen <= l && - pattern_match(mp->line, line - mp->llen, - NULL, ea) && - pattern_match(mp->word, word - mp->wlen, - ea, NULL)) { - line -= mp->llen; - word -= mp->wlen; - l -= mp->llen; - wlen -= mp->wlen; - rl += mp->wlen; - t = 1; - } + for (ms = bmatchers; ms && !t; ms = ms->next) { + mp = ms->matcher; + if (!mp->flags && mp->wlen <= wlen && mp->llen <= l && + pattern_match(mp->line, line - mp->llen, + NULL, ea) && + pattern_match(mp->word, word - mp->wlen, + ea, NULL)) { + line -= mp->llen; + word -= mp->wlen; + l -= mp->llen; + wlen -= mp->wlen; + rl += mp->wlen; + t = 1; } } if (!t) @@ -2404,84 +2530,83 @@ bld_new_sfx(int ol, char *ow, int nl, char *nw, int *olp, int *nlp, Cline *lp) } while (ol && nl) { if (ow[-1] != nw[-1]) { - for (t = 0, ms = bmstack; ms && !t; ms = ms->next) { - for (mp = ms->matcher; mp && !t; mp = mp->next) { - if (!mp->flags && mp->wlen > 0 && mp->llen > 0 && - mp->wlen <= ol && mp->wlen <= nl) { - if (pattern_match(mp->word, ow - mp->wlen, - NULL, ea)) { - if (mp->llen + 1 > llen) { - if (llen) - zfree(line, llen); - line = (char *) zalloc(llen = mp->llen + 20); - } - if ((bl = bld_line_sfx(mp->line, line, line, - nl, nw, ea))) { - if (p != ow) { - char sav = *p; - - *p = '\0'; - n = getcline(NULL, 0, dupstring(ow), - p - ow, 0); - *p = sav; - if (l) - l->next = n; - else - ret = n; - l = n; - } - line[mp->llen] = '\0'; - n = getcline(dupstring(line), mp->llen, - NULL, 0, CLF_DIFF); + for (t = 0, ms = bmatchers; ms && !t; ms = ms->next) { + mp = ms->matcher; + if (!mp->flags && mp->wlen > 0 && mp->llen > 0 && + mp->wlen <= ol && mp->wlen <= nl) { + if (pattern_match(mp->word, ow - mp->wlen, + NULL, ea)) { + if (mp->llen + 1 > llen) { + if (llen) + zfree(line, llen); + line = (char *) zalloc(llen = mp->llen + 20); + } + if ((bl = bld_line_sfx(mp->line, line, line, + nl, nw, ea))) { + if (p != ow) { + char sav = *p; + + *p = '\0'; + n = getcline(NULL, 0, dupstring(ow), + p - ow, 0); + *p = sav; if (l) l->next = n; else ret = n; l = n; - ow -= mp->wlen; - nw -= bl; - ol -= mp->wlen; - nl -= bl; - p = ow; - t = 1; } - } else if (pattern_match(mp->word, nw - mp->wlen, - NULL, ea)) { - if (mp->llen + 1 > llen) { - if (llen) - zfree(line, llen); - line = (char *) zalloc(llen = mp->llen + 20); - } - if ((bl = bld_line_sfx(mp->line, line, line, - ol, ow, ea))) { - if (p != ow) { - char sav = *p; - - *p = '\0'; - n = getcline(NULL, 0, dupstring(ow), - p - ow, 0); - *p = sav; - if (l) - l->next = n; - else - ret = n; - l = n; - } - line[mp->llen] = '\0'; - n = getcline(dupstring(line), mp->llen, - NULL, 0, CLF_DIFF); + line[mp->llen] = '\0'; + n = getcline(dupstring(line), mp->llen, + NULL, 0, CLF_DIFF); + if (l) + l->next = n; + else + ret = n; + l = n; + ow -= mp->wlen; + nw -= bl; + ol -= mp->wlen; + nl -= bl; + p = ow; + t = 1; + } + } else if (pattern_match(mp->word, nw - mp->wlen, + NULL, ea)) { + if (mp->llen + 1 > llen) { + if (llen) + zfree(line, llen); + line = (char *) zalloc(llen = mp->llen + 20); + } + if ((bl = bld_line_sfx(mp->line, line, line, + ol, ow, ea))) { + if (p != ow) { + char sav = *p; + + *p = '\0'; + n = getcline(NULL, 0, dupstring(ow), + p - ow, 0); + *p = sav; if (l) l->next = n; else ret = n; l = n; - ow -= bl; - nw -= mp->wlen; - ol -= bl; - nl -= mp->wlen; - p = ow; - t = 1; } + line[mp->llen] = '\0'; + n = getcline(dupstring(line), mp->llen, + NULL, 0, CLF_DIFF); + if (l) + l->next = n; + else + ret = n; + l = n; + ow -= bl; + nw -= mp->wlen; + ol -= bl; + nl -= mp->wlen; + p = ow; + t = 1; } } } @@ -2554,21 +2679,20 @@ join_new_sfx(Cline line, int len, char *word, int *missp) len--; ind++; } else { - for (t = 0, ms = bmstack; ms && !t; ms = ms->next) { - for (mp = ms->matcher; mp && !t; mp = mp->next) { - if (!mp->flags && mp->wlen > 0 && mp->llen > 0 && - mp->wlen <= len && mp->llen <= len && - pattern_match(mp->word, word - mp->wlen, - NULL, ea) && - pattern_match(mp->line, p - mp->llen, - ea, NULL)) { - p -= mp->llen; - word -= mp->wlen; - ll -= mp->llen; - len -= mp->wlen; - ind += mp->wlen; - t = 1; - } + for (t = 0, ms = bmatchers; ms && !t; ms = ms->next) { + mp = ms->matcher; + if (!mp->flags && mp->wlen > 0 && mp->llen > 0 && + mp->wlen <= len && mp->llen <= len && + pattern_match(mp->word, word - mp->wlen, + NULL, ea) && + pattern_match(mp->line, p - mp->llen, + ea, NULL)) { + p -= mp->llen; + word -= mp->wlen; + ll -= mp->llen; + len -= mp->wlen; + ind += mp->wlen; + t = 1; } } if (!t) @@ -2663,7 +2787,7 @@ join_new_sfx(Cline line, int len, char *word, int *missp) static void bld_sfx(Cline o, Cline n) { - if (o->flags & CLF_NEW) { + if (o->flags & CLF_SNEW) { int miss; o->suffix = join_new_sfx(o->suffix, n->wlen, n->word, &miss); @@ -2679,7 +2803,7 @@ bld_sfx(Cline o, Cline n) new = dupstring(n->word); newl = n->wlen; } else if (!strpfx(o->word, n->word)) { - o->flags |= CLF_NEW; + o->flags |= CLF_SNEW; o->suffix = bld_new_sfx(o->wlen, o->word, n->wlen, n->word, &mol, &mnl, NULL); newl = 0; @@ -2732,7 +2856,7 @@ join_clines(Cline o, Cline n) n = q; } } - if (n->flags & CLF_MID) { + if (n && n->flags & CLF_MID) { while (o && !(o->flags & CLF_MID)) { o->word = NULL; o->flags |= CLF_DIFF; @@ -3128,6 +3252,7 @@ inst_cline(Cline l, int pl, int sl) } l = l->next; } + lastend = cs; /* Now place the cursor. Preferably in a position where something * is missing, otherwise in a place where the string differs from * any of the matches, or just leave it at the end. */ @@ -3281,6 +3406,7 @@ match_pfx(char *l, char *w, Cline *nlp, int *lp, Cline *rlp, int *bplp) * to continue after the matched portion. */ w = q; iw = j; + lw = k; l = p; il = jj; ll = kk; @@ -3501,6 +3627,7 @@ match_sfx(char *l, char *w, Cline *nlp, int *lp, int *bslp) } w = q + 1; iw = j; + lw = k; l = p + 1; il = jj; ll = kk; @@ -3765,6 +3892,7 @@ instmatch(Cmatch m) inststrlen(m->suf, 1, (l = strlen(m->suf))); r += l; } + lastend = cs; cs = ocs; return r; } @@ -3777,10 +3905,10 @@ instmatch(Cmatch m) void addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, char *suf, char *group, char *rems, char *remf, char *ign, - int flags, int aflags, Cmatcher match, char **argv) + int flags, int aflags, Cmatcher match, char *exp, char **argv) { - char *s, *t, *e, *me, *te, *ms, *lipre = NULL, *lpre, *lsuf, **aign = NULL; - int lpl, lsl, i, pl, sl, test, bpl, bsl, lsm, llpl; + char *s, *t, *e, *me, *ms, *lipre = NULL, *lpre, *lsuf, **aign = NULL; + int lpl, lsl, i, pl, sl, test, bpl, bsl, llpl, llsl; Aminfo ai; Cline lc = NULL; LinkList l; @@ -3788,43 +3916,39 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, struct cmlist mst; Cmlist oms = mstack; - /* Select the set of matches. */ - if (aflags & CAF_ALT) { - l = fmatches; - ai = fainfo; - } else { - l = matches; - ai = ainfo; - } - /* Store the matcher in our stack of matchers. */ - if (match) { - mst.next = mstack; - mst.matcher = match; - mstack = &mst; - if (had_lm && mnum) - bmstack1.matcher = NULL; - else { - bmstack1.matcher = match; - had_lm = 1; - } - addlinknode(matchers, match); - match->refc++; - } else { - bmstack1.matcher = NULL; - if (mnum) - had_lm = 1; - } /* Use menu-completion (-U)? */ if ((aflags & CAF_MENU) && isset(AUTOMENU)) usemenu = 1; - /* Get the suffixes to ignore. */ - if (ign) - aign = get_user_var(ign); /* Switch back to the heap that was used when the completion widget * was invoked. */ SWITCHHEAPS(compheap) { HEAPALLOC { + if (exp) { + expl = (Cexpl) halloc(sizeof(struct cexpl)); + expl->count = expl->fcount = 0; + expl->str = dupstring(exp); + } else + expl = NULL; + + /* Store the matcher in our stack of matchers. */ + if (match) { + mst.next = mstack; + mst.matcher = match; + mstack = &mst; + + if (!mnum) + add_bmatchers(match); + + addlinknode(matchers, match); + match->refc++; + } + if (mnum && (mstack || bmatchers)) + update_bmatchers(); + + /* Get the suffixes to ignore. */ + if (ign) + aign = get_user_var(ign); /* Get the contents of the completion variables if we have * to perform matching. */ if (aflags & CAF_MATCH) { @@ -3832,6 +3956,7 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, lpre = dupstring(compprefix); llpl = strlen(lpre); lsuf = dupstring(compsuffix); + llsl = strlen(lsuf); } /* Now duplicate the strings we have from the command line. */ if (ipre) @@ -3848,8 +3973,6 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, lsl = strlen(psuf); } else lsl = 0; - if (aflags & CAF_MATCH) - lsm = (psuf ? !strcmp(psuf, lsuf) : (!lsuf || !*lsuf)); if (pre) pre = dupstring(pre); if (suf) @@ -3865,6 +3988,17 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, begcmgroup(group, (aflags & CAF_NOSORT)); if (aflags & CAF_NOSORT) mgroup->flags |= CGF_NOSORT; + } else { + endcmgroup(NULL); + begcmgroup("default", 0); + } + /* Select the set of matches. */ + if (aflags & CAF_ALT) { + l = fmatches; + ai = fainfo; + } else { + l = matches; + ai = ainfo; } if (remf) { remf = dupstring(remf); @@ -3908,19 +4042,19 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, } if (aflags & CAF_MATCH) { /* Do the matching. */ - t = (ppre ? dyncat(ppre, s) : s); - pl = sl + lpl; - if ((test = (llpl <= pl && !strncmp(t, lpre, pl)))) - test = lsm; + test = (sl >= llpl + llsl && + strpfx(lpre, s) && strsfx(lsuf, s)); if (!test && mstack && - (ms = comp_match(lpre, lsuf, - (psuf ? dyncat(t, psuf) : t), + (ms = comp_match(lpre, lsuf, s, &lc, (aflags & CAF_QUOTE), &bpl, &bsl))) test = 1; + if (!test) continue; - me = e = s + sl; + pl = sl - llsl; + me = s + sl - llsl; + e = s + llpl; } else { e = s; me = s + sl; @@ -3928,8 +4062,10 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, } /* Quoting? */ if (!(aflags & CAF_QUOTE)) { - te = s + pl; - s = quotename(s, &e, te, &pl); + int tmp = me - s; + + s = quotename(s, &e, me, &tmp); + me = s + tmp; sl = strlen(s); } /* The rest is almost the same as in addmatch(). */ @@ -3944,31 +4080,48 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, if (ppre) t = dyncat(ppre, t); if (!ms && mstack) { + int bl = ((aflags & CAF_MATCH) ? llpl : 0); Cline *clp = &lc, tlc; char *ss = dupstring(s), *ee = me + (ss - s); if (ppre && *ppre) { - *clp = str_cline(ppre, strlen(ppre), &tlc); + *clp = tlc = getcline(NULL, 0, ppre, lpl, CLF_VAR); clp = &(tlc->next); } - if (ee != ss + sl || (lpsuf && *lpsuf)) { - *clp = tlc = getcline(ss, ee - ss, + if (bl) { + *clp = str_cline(ss, bl, &tlc); + clp = &(tlc->next); + } + if (ee != ss + sl) { + *clp = tlc = getcline(ss + bl, ee - ss - bl, NULL, 0, CLF_MID); clp = &(tlc->next); - if (ee != ss + sl) { - *clp = str_cline(ee, (ss + sl) - ee, &tlc); - clp = &(tlc->next); - } - if (lpsuf && *lpsuf) { - *clp = str_cline(lpsuf, strlen(lpsuf), &tlc); - clp = &(tlc->next); - } + *clp = str_cline(ee, (ss + sl) - ee, &tlc); + clp = &(tlc->next); } else { - *clp = tlc = getcline(NULL, 0, ss, sl, + *clp = tlc = getcline(NULL, 0, ss + bl, sl - bl, + CLF_END | CLF_VAR); + clp = &(tlc->next); + } + if (psuf && *psuf) { + *clp = tlc = getcline(NULL, 0, psuf, lsl, CLF_END | CLF_VAR); clp = &(tlc->next); } *clp = NULL; + } else if (mstack) { + Cline tlc; + + if (ppre && *ppre) { + tlc = getcline(NULL, 0, ppre, lpl, CLF_VAR); + tlc->next = lc; + lc = tlc; + } + if (psuf && *psuf) { + for (tlc = lc; tlc->next; tlc = tlc->next); + tlc->next = getcline(NULL, 0, psuf, lsl, + CLF_END | CLF_VAR); + } } if (ipre && *ipre) { Cline tlc = prepend_cline(ipre, lc); @@ -4047,6 +4200,8 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre, } } compnmatches = mnum; + if (exp) + addexpl(); } LASTALLOC; } SWITCHBACKHEAPS; @@ -4129,8 +4284,10 @@ addmatch(char *s, char *t) mpl = fpl; msl = fsl; } else { if ((cp = filecomp)) { - if ((test = domatch(s, filecomp, 0))) + if ((test = domatch(s, filecomp, 0))) { + e = s + sl; cc = 1; + } } else { e = s + sl - fsl; if ((test = !strncmp(s, fpre, fpl))) @@ -4168,6 +4325,7 @@ addmatch(char *s, char *t) strcat(tt, s); if (lpsuf) strcat(tt, lpsuf); + e += (tt - s); untokenize(s = tt); sl = strlen(s); } @@ -4196,9 +4354,10 @@ addmatch(char *s, char *t) ((addwhat & CC_EXCMDS) && !(hn->flags & DISABLED)))) || ((addwhat & CC_BINDINGS) && !(hn->flags & DISABLED))))) { if (sl >= rpl + rsl || mstack) { - if (cp) + if (cp) { test = domatch(s, patcomp, 0); - else { + e = s + sl; + } else { e = s + sl - rsl; if ((test = !strncmp(s, rpre, rpl))) if ((test = !strcmp(e, rsuf))) { @@ -4888,9 +5047,11 @@ makecomplist(char *s, int incmd, int lst) { struct cmlist ms; Cmlist m; + char *os = s; - /* If we already have a list from a previous execution of this * - * function, skip the list building code. */ + /* We build a copy of the list of matchers to use to make sure that this + * works even if a shell function called from the completion code changes + * the global matchers. */ if ((m = cmatcher)) { Cmlist mm, *mp = &mm; @@ -4906,16 +5067,19 @@ makecomplist(char *s, int incmd, int lst) m = mm; } compmatcher = 1; - bmstack = &bmstack1; - bmstack1.next = &bmstack0; - bmstack0.next = NULL; - bmstack0.matcher = bmstack1.matcher = NULL; + + /* Walk through the global matchers. */ for (;;) { + bmatchers = NULL; if (m) { ms.next = NULL; ms.matcher = m->matcher; mstack = &ms; - bmstack0.matcher = m->matcher; + + /* Store the matchers used in the bmatchers list which is used + * when building new parts for the string to insert into the + * line. */ + add_bmatchers(m->matcher); } else mstack = NULL; @@ -4932,12 +5096,12 @@ makecomplist(char *s, int incmd, int lst) lastambig = 0; amatches = 0; mnum = 0; - had_lm = 0; begcmgroup("default", 0); ccused = newlinklist(); ccstack = newlinklist(); + s = dupstring(os); if (compfunc) callcompfunc(s, compfunc); else @@ -5004,7 +5168,7 @@ ctokenize(char *p) /**/ char * -comp_str(int *ipl, int *pl) +comp_str(int *ipl, int *pl, int untok) { char *p = dupstring(compprefix); char *s = dupstring(compsuffix); @@ -5012,12 +5176,14 @@ comp_str(int *ipl, int *pl) char *str; int lp, ls, lip; - ctokenize(p); - remnulargs(p); - ctokenize(s); - remnulargs(s); - ctokenize(ip); - remnulargs(ip); + if (!untok) { + ctokenize(p); + remnulargs(p); + ctokenize(s); + remnulargs(s); + ctokenize(ip); + remnulargs(ip); + } ls = strlen(s); lip = strlen(ip); lp = strlen(p); @@ -5041,7 +5207,7 @@ makecomplistcall(Compctl cc) SWITCHHEAPS(compheap) { HEAPALLOC { int ooffs = offs, lip, lp; - char *str = comp_str(&lip, &lp); + char *str = comp_str(&lip, &lp, 0); offs = lip + lp; cc->refc++; @@ -5073,7 +5239,7 @@ makecomplistctl(int flags) SWITCHHEAPS(compheap) { HEAPALLOC { int ooffs = offs, lip, lp; - char *str = comp_str(&lip, &lp), *t; + char *str = comp_str(&lip, &lp, 0), *t; char *os = cmdstr, **ow = clwords, **p, **q; int on = clwnum, op = clwpos; @@ -5571,19 +5737,16 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) ms.next = mstack; ms.matcher = cc->matcher; mstack = &ms; - if (had_lm && mnum) - bmstack1.matcher = NULL; - else { - bmstack1.matcher = cc->matcher; - had_lm = 1; - } + + if (!mnum) + add_bmatchers(cc->matcher); + addlinknode(matchers, cc->matcher); cc->matcher->refc++; - } else { - bmstack1.matcher = NULL; - if (mnum) - had_lm = 1; } + if (mnum && (mstack || bmatchers)) + update_bmatchers(); + /* Insert the prefix (compctl -P), if any. */ if (cc->prefix) { int pl = 0; @@ -6344,7 +6507,8 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) } if ((tt = cc->explain)) { - if (cc->mask & CC_EXPANDEXPL && !parsestr(tt = dupstring(tt))) { + tt = dupstring(tt); + if ((cc->mask & CC_EXPANDEXPL) && !parsestr(tt)) { singsub(&tt); untokenize(tt); } @@ -6358,7 +6522,8 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) begcmgroup("default", 0); } else if ((tt = cc->explain)) { - if (cc->mask & CC_EXPANDEXPL && !parsestr(tt = dupstring(tt))) { + tt = dupstring(tt); + if ((cc->mask & CC_EXPANDEXPL) && !parsestr(tt)) { singsub(&tt); untokenize(tt); } @@ -6631,7 +6796,7 @@ begcmgroup(char *n, int nu) } } mgroup = (Cmgroup) halloc(sizeof(struct cmgroup)); - mgroup->name = n; + mgroup->name = dupstring(n); mgroup->flags = mgroup->lcount = mgroup->mcount = 0; mgroup->matches = NULL; mgroup->ylist = NULL; @@ -6872,7 +7037,7 @@ do_ambiguous(void) /* If we have to insert the first match, call do_single(). This is * * how REC_EXACT takes effect. We effectively turn the ambiguous * * completion into an unambiguous one. */ - if (ainfo && ainfo->exact == 1 && isset(RECEXACT) && !fromcomp && + if (ainfo && ainfo->exact == 1 && isset(RECEXACT) && !(fromcomp & FC_LINE) && (usemenu == 0 || unset(AUTOMENU))) { do_single(ainfo->exactm); invalidatelist(); @@ -6945,7 +7110,6 @@ do_ambiguous(void) merge_cline(lc, ps, lp, NULL, 0, 0); } inst_cline(lc, pl, sl); - } else { inststrlen(ps, 1, -1); ocs = cs; @@ -6966,6 +7130,7 @@ do_ambiguous(void) cs -= brsl; inststrlen(brend, 1, -1); } + lastend = cs; cs = ocs; } /* la is non-zero if listambiguous may be used. Copying and @@ -6973,11 +7138,13 @@ do_ambiguous(void) * solution. Really. */ la = (ll != oll || strncmp(oline, (char *) line, ll)); - /* If REC_EXACT and AUTO_MENU are set and what we inserted is an * - * exact match, we want menu completion the next time round * - * so we set fromcomp,to ensure that the word on the line is not * - * taken as an exact match. */ - fromcomp = isset(AUTOMENU); + /* If REC_EXACT and AUTO_MENU are set and what we inserted is an * + * exact match, we want menu completion the next time round * + * so we set fromcomp,to ensure that the word on the line is not * + * taken as an exact match. Also we remember if we just moved the * + * cursor into the word. */ + fromcomp = ((isset(AUTOMENU) ? FC_LINE : 0) | + ((atend && cs != lastend) ? FC_INWORD : 0)); /* * If the LIST_AMBIGUOUS option (meaning roughly `show a list only * |