From cedd1006e661b990aaa8881c2efd4116bed574a3 Mon Sep 17 00:00:00 2001 From: Sven Wischnowsky Date: Tue, 13 Jun 2000 09:05:35 +0000 Subject: fixes for calling compfiles, for completing words with special characters; make compfiles optimisations work with globcomplete and simple match (sunsite isn't responding) --- ChangeLog | 8 ++ Completion/Core/_path_files | 11 +-- Src/Zle/complete.c | 29 +++++-- Src/Zle/compmatch.c | 2 +- Src/Zle/computil.c | 194 ++++++++++++++++++++++++++++++++++++++------ 5 files changed, 204 insertions(+), 40 deletions(-) diff --git a/ChangeLog b/ChangeLog index 90fe5e90e..d3b455a80 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2000-06-13 Sven Wischnowsky + + * ?????: Completion/Core/_path_files, Src/Zle/complete.c, + Src/Zle/compmatch.c, Src/Zle/computil.c: fixes for calling + compfiles, for completing words with special characters; make + compfiles optimisations work with globcomplete and simple match + specs + 2000-06-12 Peter Stephenson * 11867: Src/builtin.c, Src/params.c, Src/zsh.h, diff --git a/Completion/Core/_path_files b/Completion/Core/_path_files index 5673e7c4a..7f6f83184 100644 --- a/Completion/Core/_path_files +++ b/Completion/Core/_path_files @@ -5,7 +5,7 @@ local linepath realpath donepath prepath testpath exppath skips skipped local tmp1 tmp2 tmp3 tmp4 i orig eorig pre suf tpre tsuf opre osuf cpre -local pats haspats ignore pfxsfx sopt gopt opt sdirs ignpar +local pats haspats ignore pfxsfx sopt gopt opt sdirs ignpar cfopt local nm=$compstate[nmatches] menu matcher mopts sort match mid typeset -U prepaths exppaths @@ -185,6 +185,7 @@ eorig="$orig" [[ $compstate[insert] = (*menu|[0-9]*) || -n "$_comp_correct" || ( -n "$compstate[pattern_match]" && "${orig#\~}" != (|*[^\\])[][*?#~^\|\<\>]* ) ]] && menu=yes +[[ -n "$_comp_correct" ]] && cfopt=- # Now let's have a closer look at the string to complete. @@ -222,7 +223,7 @@ if [[ "$pre[1]" = \~ && -z "$compstate[quote]" ]]; then elif [[ tmp -le $#dirstack ]]; then realpath=$dirstack[tmp]/ else - _message 'not directory stack entries' + _message 'not enough directory stack entries' return 1 fi elif [[ "$linepath" = [-+] ]]; then @@ -313,11 +314,11 @@ for prepath in "$prepaths[@]"; do # Get the matching files by globbing. if [[ "$tpre$tsuf" = */* ]]; then - compfiles -P tmp1 "$skipped" "$_matcher" "$sdirs" + compfiles -P$cfopt tmp1 "$skipped" "$_matcher" "$sdirs" elif [[ "$sopt" = *[/f]* ]]; then - compfiles -p tmp1 "$skipped" "$_matcher" "$sdirs" "$pats" + compfiles -p$cfopt tmp1 "$skipped" "$_matcher" "$sdirs" "$pats[@]" else - compfiles -p tmp1 "$skipped" "$_matcher" '' "$pats" + compfiles -p$cfopt tmp1 "$skipped" "$_matcher" '' "$pats[@]" fi tmp1=( $~tmp1 ) diff --git a/Src/Zle/complete.c b/Src/Zle/complete.c index 1a659f781..11f6d24ef 100644 --- a/Src/Zle/complete.c +++ b/Src/Zle/complete.c @@ -204,16 +204,20 @@ parse_cmatcher(char *name, char *s) case 'R': fl = CMF_RIGHT | CMF_LINE; break; case 'M': fl = CMF_LINE; break; default: - zwarnnam(name, "unknown match specification character `%c'", NULL, *s); + if (name) + zwarnnam(name, "unknown match specification character `%c'", + NULL, *s); return pcm_err; } if (s[1] != ':') { - zwarnnam(name, "missing `:'", NULL, 0); + if (name) + zwarnnam(name, "missing `:'", NULL, 0); return pcm_err; } s += 2; if (!*s) { - zwarnnam(name, "missing patterns", NULL, 0); + if (name) + zwarnnam(name, "missing patterns", NULL, 0); return pcm_err; } if (fl & CMF_LEFT) { @@ -225,7 +229,8 @@ parse_cmatcher(char *name, char *s) s++; if (!*s || !*++s) { - zwarnnam(name, "missing line pattern", NULL, 0); + if (name) + zwarnnam(name, "missing line pattern", NULL, 0); return pcm_err; } } else @@ -242,10 +247,12 @@ parse_cmatcher(char *name, char *s) ll = 0; } if ((fl & CMF_RIGHT) && (!*s || !*++s)) { - zwarnnam(name, "missing right anchor", NULL, 0); + if (name) + zwarnnam(name, "missing right anchor", NULL, 0); } else if (!(fl & CMF_RIGHT)) { if (!*s) { - zwarnnam(name, "missing word pattern", NULL, 0); + if (name) + zwarnnam(name, "missing word pattern", NULL, 0); return pcm_err; } s++; @@ -262,7 +269,8 @@ parse_cmatcher(char *name, char *s) if (err) return pcm_err; if (!*s) { - zwarnnam(name, "missing word pattern", NULL, 0); + if (name) + zwarnnam(name, "missing word pattern", NULL, 0); return pcm_err; } s++; @@ -271,7 +279,8 @@ parse_cmatcher(char *name, char *s) if (*s == '*') { if (!(fl & (CMF_LEFT | CMF_RIGHT))) { - zwarnnam(name, "need anchor for `*'", NULL, 0); + if (name) + zwarnnam(name, "need anchor for `*'", NULL, 0); return pcm_err; } word = NULL; @@ -284,7 +293,9 @@ parse_cmatcher(char *name, char *s) word = parse_pattern(name, &s, &wl, 0, &err); if (!word && !line) { - zwarnnam(name, "need non-empty word or line pattern", NULL, 0); + if (name) + zwarnnam(name, "need non-empty word or line pattern", + NULL, 0); return pcm_err; } } diff --git a/Src/Zle/compmatch.c b/Src/Zle/compmatch.c index 4671b9583..8cdfddede 100644 --- a/Src/Zle/compmatch.c +++ b/Src/Zle/compmatch.c @@ -1029,7 +1029,7 @@ comp_match(char *pfx, char *sfx, char *w, Patprog cp, Cline *clp, int qu, * corresponding character. */ /**/ -static int +mod_export int pattern_match(Cpattern p, char *s, unsigned char *in, unsigned char *out) { unsigned char c; diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c index ecb7ca3e1..d32f77a1c 100644 --- a/Src/Zle/computil.c +++ b/Src/Zle/computil.c @@ -3059,27 +3059,164 @@ cfp_test_exact(LinkList names, char *skipped) return (found ? ret : NULL); } +static char * +cfp_matcher_pats(char *matcher, char *add) +{ + Cmatcher m = parse_cmatcher(NULL, matcher); + + if (m && m != pcm_err) { + char *tmp; + int al = strlen(add), tl; + VARARR(Cmatcher, ms, al); + Cmatcher *mp; + Cpattern stopp; + int stopl = 0; + + memset(ms, 0, al * sizeof(Cmatcher)); + + for (; m && *add; m = m->next) { + stopp = NULL; + if (!(m->flags & (CMF_LEFT|CMF_RIGHT))) { + if (m->llen == 1 && m->wlen == 1) { + for (tmp = add, tl = al, mp = ms; tl; tl--, tmp++, mp++) { + if (pattern_match(m->line, tmp, NULL, NULL)) { + if (*mp) { + *tmp = '\0'; + al = tmp - add; + break; + } else + *mp = m; + } + } + } else { + stopp = m->line; + stopl = m->llen; + } + } else if (m->flags & CMF_RIGHT) { + if (m->wlen < 0 && !m->llen && m->ralen == 1) { + for (tmp = add, tl = al, mp = ms; tl; tl--, tmp++, mp++) { + if (pattern_match(m->right, tmp, NULL, NULL)) { + if (*mp) { + *tmp = '\0'; + al = tmp - add; + break; + } else + *mp = m; + } + } + } else if (m->llen) { + stopp = m->line; + stopl = m->llen; + } else { + stopp = m->right; + stopl = m->ralen; + } + } else { + if (!m->lalen) + return ""; + + stopp = m->left; + stopl = m->lalen; + } + if (stopp) + for (tmp = add, tl = al; tl >= stopl; tl--, tmp++) + if (pattern_match(stopp, tmp, NULL, NULL)) { + *tmp = '\0'; + al = tmp - add; + break; + } + } + if (*add) { + char *ret = "", buf[259]; + + for (mp = ms; *add; add++, mp++) { + if (!(m = *mp)) { + buf[0] = *add; + buf[1] = '\0'; + } else if (m->flags & CMF_RIGHT) { + buf[0] = '*'; + buf[1] = *add; + buf[2] = '\0'; + } else { + unsigned char *t, c; + char *p = buf; + int i; + + for (i = 256, t = m->word->tab; i--; t++) + if (*t) + break; + if (i) { + t = m->word->tab; + *p++ = '['; + if (m->line->equiv && m->word->equiv) { + *p++ = *add; + c = m->line->tab[STOUC(*add)]; + for (i = 0; i < 256; i++) + if (m->word->tab[i] == c) { + *p++ = (char) i; + break; + } + } else { + if (*add == ']' || t[STOUC(']')]) + *p++ = ']'; + for (i = 0; i < 256; i++, t++) + if (*t && ((char) i) != *add && + i != ']' && i != '-' && + i != '^' && i != '!') + *p++ = (char) i; + *p++ = *add; + t = m->word->tab; + if (*add != '^' && t[STOUC('^')]) + *p++ = '^'; + if (*add != '!' && t[STOUC('!')]) + *p++ = '!'; + if (*add != '-' && t[STOUC('-')]) + *p++ = '-'; + } + *p++ = ']'; + *p = '\0'; + } else { + *p = '?'; + p[1] = '\0'; + } + } + ret = dyncat(ret, buf); + } + return ret; + } + } + return add; +} + static void cfp_opt_pats(char **pats, char *matcher) { char *add, **p, *q, *t, *s; - /**** For now we don't try to improve the patterns if there are match - * specs. We should work on this some more... - * - * And another one: we can do this with comppatmatch if the word - * doesn't contain wildcards, unless the approximate matcher is - * active. Better: unless there is a compadd function. I.e., we - * need one more piece of information from the shell code, at least - * I'd prefer to get it from _path_files in case we find other - * conditions for not trying to improve patterns. */ - - if ((comppatmatch && *comppatmatch) || *matcher || - !compprefix || !*compprefix) + if (!compprefix || !*compprefix) return; - add = rembslash(compprefix); - + if (comppatmatch && *comppatmatch) { + tokenize(t = rembslash(dyncat(compprefix, compsuffix))); + remnulargs(t); + if (haswilds(t)) + return; + } + add = (char *) zhalloc(sizeof(compprefix) * 2 + 1); + for (s = compprefix, t = add; *s; s++) { + if (*s != '\\' || !s[1] || s[1] == '*' || s[1] == '?' || + s[1] == '<' || s[1] == '>' || s[1] == '(' || s[1] == ')' || + s[1] == '[' || s[1] == ']' || s[1] == '|' || s[1] == '#' || + s[1] == '^' || s[1] == '~') { + if ((s == compprefix || s[-1] != '\\') && + (*s == '*' || *s == '?' || *s == '<' || *s == '>' || + *s == '(' || *s == ')' || *s == '[' || *s == ']' || + *s == '|' || *s == '#' || *s == '^' || *s == '~')) + *t++ = '\\'; + *t++ = *s; + } + } + *t = '\0'; for (p = pats; *add && (q = *p); p++) { if (*q) { q = dupstring(q); @@ -3124,6 +3261,9 @@ cfp_opt_pats(char **pats, char *matcher) } } if (*add) { + if (*matcher && !(add = cfp_matcher_pats(matcher, add))) + return; + for (p = pats; *p; p++) if (**p == '*') *p = dyncat(add, *p); @@ -3189,8 +3329,8 @@ cfp_add_sdirs(LinkList final, LinkList orig, char *skipped, char *sdirs) } static LinkList -cf_pats(int dirs, LinkList names, char *skipped, char *matcher, char *sdirs, - char **pats) +cf_pats(int dirs, int noopt, LinkList names, char *skipped, char *matcher, + char *sdirs, char **pats) { LinkList ret; char *dpats[2]; @@ -3203,7 +3343,8 @@ cf_pats(int dirs, LinkList names, char *skipped, char *matcher, char *sdirs, dpats[1] = NULL; pats = dpats; } - cfp_opt_pats(pats, matcher); + if (!noopt) + cfp_opt_pats(pats, matcher); return cfp_add_sdirs(cfp_bld_pats(dirs, names, skipped, pats), names, skipped, sdirs); @@ -3255,14 +3396,13 @@ bin_compfiles(char *nam, char **args, char *ops, int func) zwarnnam(nam, "missing option: %s", *args, 0); return 1; } - if (args[0][2]) { - zwarnnam(nam, "invalid option: %s", *args, 0); - return 1; - } switch (args[0][1]) { case 'p': case 'P': - { + if (args[0][2] && (args[0][2] != '-' || args[0][3])) { + zwarnnam(nam, "invalid option: %s", *args, 0); + return 1; + } else { char **tmp; LinkList l; @@ -3277,12 +3417,16 @@ bin_compfiles(char *nam, char **args, char *ops, int func) } for (l = newlinklist(); *tmp; tmp++) addlinknode(l, *tmp); - set_list_array(args[1], cf_pats((args[0][1] == 'P'), l, args[2], - args[3], args[4], args + 5)); + set_list_array(args[1], cf_pats((args[0][1] == 'P'), !!args[0][2], + l, args[2], args[3], args[4], + args + 5)); return 0; } case 'i': - { + if (args[0][2]) { + zwarnnam(nam, "invalid option: %s", *args, 0); + return 1; + } else { char **tmp; LinkList l; -- cgit 1.4.1