From f9a6f521d6475360bee03808ced1f301983bb700 Mon Sep 17 00:00:00 2001 From: Tanaka Akira Date: Mon, 8 Nov 1999 10:26:20 +0000 Subject: zsh-workers/8588 --- Completion/Core/_path_files | 29 +++++--- Doc/Zsh/compwid.yo | 11 +++ Doc/Zsh/mod_computil.yo | 17 ++++- Src/Zle/comp.h | 9 ++- Src/Zle/compcore.c | 171 ++++++++++++++++++++++++++++++-------------- Src/Zle/compctl.c | 67 ++++++++++++----- Src/Zle/complete.c | 13 +++- Src/Zle/compmatch.c | 14 +--- Src/Zle/compresult.c | 15 ++-- Src/Zle/computil.c | 51 +++++++++++++ Src/Zle/computil.mdd | 2 +- Src/Zle/zle_tricky.c | 23 ++++-- Src/params.c | 6 +- 13 files changed, 312 insertions(+), 116 deletions(-) diff --git a/Completion/Core/_path_files b/Completion/Core/_path_files index 077c2608b..019fafbcb 100644 --- a/Completion/Core/_path_files +++ b/Completion/Core/_path_files @@ -233,7 +233,9 @@ for prepath in "$prepaths[@]"; do if [[ "$tmp2[1]" = */* ]]; then tmp2=( "${(@)tmp2#${prepath}${realpath}}" ) if [[ "$tmp2[1]" = */* ]]; then - exppaths=( "$exppaths[@]" ${^tmp2:h:q}/${tpre}${tsuf} ) + tmp2=( "${(@)tmp2:h}" ) + compquote tmp2 + exppaths=( "$exppaths[@]" ${^tmp2}/${tpre}${tsuf} ) else exppaths=( "$exppaths[@]" ${tpre}${tsuf} ) fi @@ -329,36 +331,39 @@ for prepath in "$prepaths[@]"; do SUFFIX="${tsuf}" fi +tmp4="$testpath" +compquote tmp1 tmp4 + if [[ -n $menu || "$compconfig[path_expand]" != *suffix* ]]; then [[ -n "$compconfig[path_cursor]" ]] && compstate[to_end]='' if [[ "$tmp3" = */* ]]; then - compadd -Qf -p "$linepath${testpath:q}" -s "/${tmp3#*/}" \ + compadd -Qf -p "$linepath$tmp4" -s "/${tmp3#*/}" \ -W "$prepath$realpath$testpath" "$ignore[@]" \ "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \ -M "r:|/=* r:|=* $match" "$group[@]" "$expl[@]" \ - - "${(@)${(@)tmp1%%/*}:q}" + - "${(@)tmp1%%/*}" else - compadd -Qf -p "$linepath${testpath:q}" \ + compadd -Qf -p "$linepath$tmp4" \ -W "$prepath$realpath$testpath" "$ignore[@]" \ "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \ -M "r:|/=* r:|=* $match" "$group[@]" "$expl[@]" \ - - "${(@)tmp1:q}" + - "$tmp1[@]" fi else if [[ "$tmp3" = */* ]]; then for i in "$tmp1[@]"; do - compadd -Qf -p "$linepath${testpath:q}" -s "/${${i#*/}:q}" \ + compadd -Qf -p "$linepath$tmp4" -s "/${i#*/}" \ -W "$prepath$realpath$testpath" "$ignore[@]" \ "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \ -M "r:|/=* r:|=* $match" "$group[@]" "$expl[@]" \ - - "${${i%%/*}:q}" + - "${i%%/*}" done else - compadd -Qf -p "$linepath${testpath:q}" \ + compadd -Qf -p "$linepath$tmp4" \ -W "$prepath$realpath$testpath" "$ignore[@]" \ "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \ -M "r:|/=* r:|=* $match" "$group[@]" "$expl[@]" \ - - "${(@)tmp1:q}" + - "$tmp1[@]" fi fi tmp4=- @@ -397,11 +402,13 @@ for prepath in "$prepaths[@]"; do if [[ -z "$tmp4" ]]; then PREFIX="${opre}${osuf}" SUFFIX="" - compadd -Qf -p "$linepath${testpath:q}" \ + tmp4="$testpath" + compquote tmp4 tmp1 + compadd -Qf -p "$linepath$tmp4" \ -W "$prepath$realpath$testpath" "$ignore[@]" \ "$addpfx[@]" "$addsfx[@]" "$remsfx[@]" \ -M "r:|/=* r:|=* $match" "$group[@]" "$expl[@]" \ - - "${(@)tmp1:q}" + - "$tmp1[@]" fi done diff --git a/Doc/Zsh/compwid.yo b/Doc/Zsh/compwid.yo index fc2285e40..b5ebb4f8e 100644 --- a/Doc/Zsh/compwid.yo +++ b/Doc/Zsh/compwid.yo @@ -184,6 +184,17 @@ When completing inside quotes, this contains the quotation character (i.e. either a single quote, a double quote, or a backtick). Otherwise it is unset. ) +item(tt(all_quotes))( +The tt(-q) option of the tt(compset) builtin command (see below) +allows breaking a quoted string into separate words and completing one +of these words. This key allows to test which types of quoted strings +are currently broken into parts this way. Its value contains one +character for each quoting level. The characters are a single quote or +a double quote for strings quoted with these characters and a +backslash for strings not starting with a quote character. The first +character in the value always corresponds to the innermost quoting +level. +) item(tt(nmatches))( The number of matches generated and accepted by the completion code so far, excluding those matches that are only accepted by ignoring the diff --git a/Doc/Zsh/mod_computil.yo b/Doc/Zsh/mod_computil.yo index cc0abc38e..541f81605 100644 --- a/Doc/Zsh/mod_computil.yo +++ b/Doc/Zsh/mod_computil.yo @@ -1,16 +1,29 @@ texinode(The computil Module)(The deltochar Module)(The complist Module)(Zsh Modules) sect(The computil Module) cindex(completion, utility) -The tt(computil) module adds four builtin commands that are used by +The tt(computil) module adds several builtin commands that are used by some of the completion functions in the shell function based completions system (see ifzman(zmanref(zshcompsys))\ ifnzman(noderef(Completion System)) -). Except for tt(compdisplay) these builtin commands are very +). Except for tt(compquote) and tt(compdisplay) these builtin +commands are very specialised and thus not very interesting when writing your own completion functions. In short, these builtin commands are: startitem() +item(tt(compquote) var(names) ...)( +There may be reasons to write completion functions that have to add +the matches using the tt(-Q) option to tt(compadd) and do the quoting +themselves. Instead of interpreting the first character of the +tt(all_quotes) key of the tt(compstate) special association and using +the tt(q) flag for parameter expansions, one can use this builtin +command. The arguements are the names of scalar or array parameters +and the values of these parameters are quoted as needed for the +innermost quoting level. + +The return value is non-zero in case of an error and zero otherwise. +) item(tt(compdisplay) var(name) var(string) var(defs) ...)( The var(defs) are strings which should be of the form `var(str)tt(:)var(descr)' (the intended use is that the var(descr) diff --git a/Src/Zle/comp.h b/Src/Zle/comp.h index 59701608e..6f3b2cd16 100644 --- a/Src/Zle/comp.h +++ b/Src/Zle/comp.h @@ -95,7 +95,7 @@ struct cmatch { char *pre; /* prefix string from -P */ char *suf; /* suffix string from -S */ char *disp; /* string to display (compadd -d) */ - char autoq; /* closing quote to add automatically */ + char *autoq; /* closing quote to add automatically */ int flags; /* see CMF_* below */ int *brpl; /* places where to put the brace prefixes */ int *brsl; /* ...and the suffixes */ @@ -115,6 +115,7 @@ struct cmatch { #define CMF_NOLIST 32 /* should not be listed */ #define CMF_DISPLINE 64 /* display strings one per line */ #define CMF_HIDE 128 /* temporarily hide this one */ +#define CMF_NOSPACE 256 /* don't add a space */ /* Stuff for completion matcher control. */ @@ -353,9 +354,11 @@ typedef void (*CLPrintFunc)(Cmgroup, Cmatch *, int, int, int, int, #define CP_ANMATCHES (1 << CPN_ANMATCHES) #define CPN_LISTLINES 26 #define CP_LISTLINES (1 << CPN_LISTLINES) +#define CPN_QUOTES 27 +#define CP_QUOTES (1 << CPN_QUOTES) -#define CP_KEYPARAMS 27 -#define CP_ALLKEYS ((unsigned int) 0x7ffffff) +#define CP_KEYPARAMS 28 +#define CP_ALLKEYS ((unsigned int) 0xfffffff) /* Hooks. */ diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c index b6e957e99..036da0c2f 100644 --- a/Src/Zle/compcore.c +++ b/Src/Zle/compcore.c @@ -101,8 +101,7 @@ int parq, eparq; /* We store the following prefixes/suffixes: * * ipre,ripre -- the ignored prefix (quoted and unquoted) * - * isuf -- the ignored suffix * - * autoq -- quotes to automatically insert */ + * isuf -- the ignored suffix */ /**/ char *ipre, *ripre, *isuf; @@ -246,10 +245,6 @@ int fromcomp; /**/ int lastend; -/* Convenience macro for calling bslashquote() (formerly quotename()). */ - -#define quotename(s, e) bslashquote(s, e, instring) - #define inststr(X) inststrlen((X),1,-1) /* Main completion entry point, called from zle. */ @@ -270,6 +265,13 @@ do_completion(Hookdef dummy, Compldat dat) ainfo = fainfo = NULL; matchers = newlinklist(); + zsfree(compqstack); + compqstack = ztrdup("\\"); + if (instring == 2) + compqstack[0] = '"'; + else if (instring) + compqstack[0] = '\''; + hasunqu = 0; useline = (lst != COMP_LIST_COMPLETE); useexact = isset(RECEXACT); @@ -603,7 +605,7 @@ callcompfunc(char *s, char *fn) zsfree(compprefix); zsfree(compsuffix); if (unset(COMPLETEINWORD)) { - tmp = quotename(s, NULL); + tmp = multiquote(s, 0); untokenize(tmp); compprefix = ztrdup(tmp); compsuffix = ztrdup(""); @@ -614,11 +616,11 @@ callcompfunc(char *s, char *fn) sav = *ss; *ss = '\0'; - tmp = quotename(s, NULL); + tmp = multiquote(s, 0); untokenize(tmp); compprefix = ztrdup(tmp); *ss = sav; - ss = quotename(ss, NULL); + ss = multiquote(ss, 0); untokenize(ss); compsuffix = ztrdup(ss); } @@ -917,6 +919,40 @@ makecomplist(char *s, int incmd, int lst) return 1; } +/**/ +char * +multiquote(char *s, int ign) +{ + char *os = s, *p = compqstack; + + if (p && *p && (ign < 1 || p[ign])) { + if (ign > 0) + p += ign; + while (*p) { + if (ign >= 0 || p[1]) + s = bslashquote(s, NULL, + (*p == '\'' ? 1 : (*p == '"' ? 2 : 0))); + p++; + } + } + return (s == os ? dupstring(s) : s); +} + +/**/ +char * +tildequote(char *s, int ign) +{ + int tilde; + + if ((tilde = (*s == '~'))) + *s = 'x'; + s = multiquote(s, ign); + if (tilde) + *s = '~'; + + return s; +} + /* Check if we have to complete a parameter name. */ /**/ @@ -1121,20 +1157,18 @@ comp_str(int *ipl, int *pl, int untok) return str; } -/* This is for compset -q. */ - /**/ int set_comp_sep(void) { int lip, lp; - char *s = comp_str(&lip, &lp, 0); + char *s = comp_str(&lip, &lp, 1); LinkList foo = newlinklist(); LinkNode n; int owe = we, owb = wb, ocs = cs, swb, swe, scs, soffs, ne = noerrs; - int tl, got = 0, i = 0, cur = -1, oll = ll, sl; + int tl, got = 0, i = 0, cur = -1, oll = ll, sl, remq; int ois = instring, oib = inbackt, noffs = lip + lp; - char *tmp, *p, *ns, *ol = (char *) line, sav, oaq = autoq, *qp, *qs; + char *tmp, *p, *ns, *ol = (char *) line, sav, *qp, *qs, *ts, qc = '\0'; if (compisuffix) s = dyncat(s, compisuffix); @@ -1154,7 +1188,8 @@ set_comp_sep(void) memcpy(tmp + 1, s, noffs); tmp[(scs = cs = 1 + noffs)] = 'x'; strcpy(tmp + 2 + noffs, s + noffs); - tmp = rembslash(tmp); + if ((remq = (*compqstack == '\\'))) + tmp = rembslash(tmp); inpush(dupstrspace(tmp), 0, NULL); line = (unsigned char *) tmp; ll = tl - 1; @@ -1217,21 +1252,31 @@ set_comp_sep(void) *p = '\''; } offs = owb; + + untokenize(ts = dupstring(ns)); + if (*ns == Snull || *ns == Dnull) { instring = (*ns == Snull ? 1 : 2); inbackt = 0; swb++; if (ns[strlen(ns) - 1] == *ns && ns[1]) swe--; - autoq = (*ns == Snull ? '\'' : '"'); + zsfree(autoq); + autoq = ztrdup(compqstack[1] ? "" : + multiquote(*ns == Snull ? "'" : "\"", 1)); + qc = (*ns == Snull ? '\'' : '"'); + ts++; } else { instring = 0; - autoq = '\0'; + zsfree(autoq); + autoq = NULL; } for (p = ns, i = swb; *p; p++, i++) { if (INULL(*p)) { - if (i < scs) - soffs--; + if (i < scs) { + if (remq && *p == Bnull && p[1]) + swb -= 2; + } if (p[1] || *p != Bnull) { if (*p == Bnull) { if (scs == i + 1) @@ -1247,17 +1292,28 @@ set_comp_sep(void) chuck(p--); } } + ns = ts; + + if (instring && strchr(compqstack, '\\')) { + int rl = strlen(ns), ql = strlen(multiquote(ns, !!compqstack[1])); + + if (ql > rl) + swb -= ql - rl; + } sav = s[(i = swb - 1)]; s[i] = '\0'; - qp = tricat(qipre, rembslash(s), ""); + qp = rembslash(s); s[i] = sav; if (swe < swb) swe = swb; swe--; sl = strlen(s); - if (swe > sl) - swe = sl, ns[swe - swb + 1] = '\0'; - qs = tricat(rembslash(s + swe), qisuf, ""); + if (swe > sl) { + swe = sl; + if (strlen(ns) > swe - swb + 1) + ns[swe - swb + 1] = '\0'; + } + qs = rembslash(s + swe); sl = strlen(ns); if (soffs > sl) soffs = sl; @@ -1265,6 +1321,11 @@ set_comp_sep(void) { int set = CP_QUOTE | CP_QUOTING, unset = 0; + p = tricat((instring ? (instring == 1 ? "'" : "\"") : "\\"), + compqstack, ""); + zsfree(compqstack); + compqstack = p; + zsfree(compquote); zsfree(compquoting); if (instring == 2) { @@ -1282,11 +1343,11 @@ set_comp_sep(void) compquoting = ztrdup(compquoting); comp_setunset(0, 0, set, unset); + zsfree(compprefix); + zsfree(compsuffix); if (unset(COMPLETEINWORD)) { untokenize(ns); - zsfree(compprefix); compprefix = ztrdup(ns); - zsfree(compsuffix); compsuffix = ztrdup(""); } else { char *ss, sav; @@ -1305,17 +1366,12 @@ set_comp_sep(void) compiprefix = ztrdup(""); zsfree(compisuffix); compisuffix = ztrdup(""); + tmp = tricat(compqiprefix, "", multiquote(qp, 1)); zsfree(compqiprefix); + compqiprefix = tmp; + tmp = tricat(multiquote(qs, 1), "", compqisuffix); zsfree(compqisuffix); - if (ois) { - compqiprefix = qp; - compqisuffix = qs; - } else { - compqiprefix = ztrdup(quotename(qp, NULL)); - zsfree(qp); - compqisuffix = ztrdup(quotename(qs, NULL)); - zsfree(qs); - } + compqisuffix = tmp; freearray(compwords); i = countlinknodes(foo); compwords = (char **) zalloc((i + 1) * sizeof(char *)); @@ -1326,7 +1382,6 @@ set_comp_sep(void) compcurrent = cur + 1; compwords[i] = NULL; } - autoq = oaq; instring = ois; inbackt = oib; @@ -1422,7 +1477,7 @@ int addmatches(Cadata dat, char **argv) { char *s, *ms, *lipre = NULL, *lisuf = NULL, *lpre = NULL, *lsuf = NULL; - char **aign = NULL, **dparr = NULL, oaq = autoq, *oppre = dat->ppre; + char **aign = NULL, **dparr = NULL, *oaq = autoq, *oppre = dat->ppre; char *oqp = qipre, *oqs = qisuf, qc, **disp = NULL; int lpl, lsl, pl, sl, bcp = 0, bcs = 0, bpadd = 0, bsadd = 0; int llpl = 0, llsl = 0, nm = mnum, gflags = 0, ohp = haspattern; @@ -1446,15 +1501,19 @@ addmatches(Cadata dat, char **argv) if (qc == '`') { instring = 0; inbackt = 0; - autoq = '\0'; + autoq = ""; } else { + char buf[2]; + instring = (qc == '\'' ? 1 : 2); inbackt = 0; - autoq = qc; + buf[0] = qc; + buf[1] = '\0'; + autoq = multiquote(buf, 1); } } else { instring = inbackt = 0; - autoq = '\0'; + autoq = NULL; } qipre = ztrdup(compqiprefix ? compqiprefix : ""); qisuf = ztrdup(compqisuffix ? compqisuffix : ""); @@ -1536,21 +1595,16 @@ addmatches(Cadata dat, char **argv) else if (lisuf) dat->isuf = lisuf; if (dat->ppre) { - if (!(dat->aflags & CAF_QUOTE)) { - dat->ppre = quotename(dat->ppre, NULL); - if ((dat->flags & CMF_FILE) && - dat->ppre[0] == '\\' && dat->ppre[1] == '~') - chuck(dat->ppre); - } else - dat->ppre = dupstring(dat->ppre); + dat->ppre = ((dat->flags & CMF_FILE) ? + tildequote(dat->ppre, + !!(dat->aflags & CAF_QUOTE)) : + multiquote(dat->ppre, + !!(dat->aflags & CAF_QUOTE))); lpl = strlen(dat->ppre); } else lpl = 0; if (dat->psuf) { - if (!(dat->aflags & CAF_QUOTE)) - dat->psuf = quotename(dat->psuf, NULL); - else - dat->psuf = dupstring(dat->psuf); + dat->psuf = multiquote(dat->psuf, !!(dat->aflags & CAF_QUOTE)); lsl = strlen(dat->psuf); } else lsl = 0; @@ -1653,6 +1707,11 @@ addmatches(Cadata dat, char **argv) dat->rems = NULL; } else if (dat->rems) dat->rems = dupstring(dat->rems); + + lpre = ((!(dat->aflags & CAF_QUOTE) && + (!dat->ppre && (dat->flags & CMF_FILE))) ? + tildequote(lpre, 1) : multiquote(lpre, 1)); + lsuf = multiquote(lsuf, 1); } /* Walk through the matches given. */ obpl = bpl; @@ -1687,12 +1746,12 @@ addmatches(Cadata dat, char **argv) if (dat->aflags & CAF_QUOTE) ms = dupstring(s); else - sl = strlen(ms = quotename(s, NULL)); + sl = strlen(ms = multiquote(s, 0)); lc = bld_parts(ms, sl, -1, NULL); isexact = 0; } else if (!(ms = comp_match(lpre, lsuf, s, cp, &lc, (!(dat->aflags & CAF_QUOTE) ? - ((dat->ppre && dat->ppre) || + (dat->ppre || !(dat->flags & CMF_FILE) ? 1 : 2) : 0), &bpl, bcp, &bsl, bcs, &isexact))) { @@ -1994,6 +2053,9 @@ add_match_data(int alt, char *str, Cline line, cm->pre = pre; cm->suf = suf; cm->flags = flags; + if (*compqstack == '\\' || + (autoq && *compqstack && compqstack[1] == '\\')) + cm->flags |= CMF_NOSPACE; if (nbrbeg) { int *p; Brinfo bp; @@ -2016,7 +2078,7 @@ add_match_data(int alt, char *str, Cline line, cm->brsl = NULL; cm->qipl = qipl; cm->qisl = qisl; - cm->autoq = (autoq ? autoq : (inbackt ? '`' : '\0')); + cm->autoq = dupstring(autoq ? autoq : (inbackt ? "`" : NULL)); cm->rems = cm->remf = cm->disp = NULL; if ((lastprebr || lastpostbr) && !hasbrpsfx(cm, lastprebr, lastpostbr)) @@ -2348,7 +2410,7 @@ dupmatch(Cmatch m, int nbeg, int nend) r->brsl = NULL; r->rems = ztrdup(m->rems); r->remf = ztrdup(m->remf); - r->autoq = m->autoq; + r->autoq = ztrdup(m->autoq); r->qipl = m->qipl; r->qisl = m->qisl; r->disp = dupstring(m->disp); @@ -2489,6 +2551,7 @@ freematch(Cmatch m, int nbeg, int nend) zsfree(m->rems); zsfree(m->remf); zsfree(m->disp); + zsfree(m->autoq); zfree(m->brpl, nbeg * sizeof(int)); zfree(m->brsl, nend * sizeof(int)); diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c index d00e317c2..cab0f55a4 100644 --- a/Src/Zle/compctl.c +++ b/Src/Zle/compctl.c @@ -1811,10 +1811,12 @@ addmatch(char *s, char *t) isalt = 1; } ms = ((addwhat == CC_FILES || addwhat == -6 || - addwhat == -5 || addwhat == -8) ? - comp_match(qfpre, qfsuf, s, filecomp, &lc, (ppre && *ppre ? 1 : 2), + addwhat == -5 || addwhat == -8) ? + comp_match(tildequote(qfpre, 1), multiquote(qfsuf, 1), + s, filecomp, &lc, (ppre && *ppre ? 1 : 2), &bpl, ppl ,&bsl, psl, &isexact) : - comp_match(fpre, fsuf, s, filecomp, &lc, 0, + comp_match(multiquote(fpre, 1), multiquote(fsuf, 1), + s, filecomp, &lc, 0, &bpl, ppl, &bsl, psl, &isexact)); if (!ms) return; @@ -1855,6 +1857,8 @@ addmatch(char *s, char *t) p1 = qlpre; s1 = qlsuf; p2 = lpre; s2 = lsuf; } + p1 = multiquote(p1, 1); s1 = multiquote(s1, 1); + p2 = multiquote(p2, 1); s2 = multiquote(s2, 1); bpt = bpl; bst = bsl; @@ -2128,21 +2132,24 @@ makecomplistctl(int flags) char *str = comp_str(&lip, &lp, 0), *t; char *os = cmdstr, **ow = clwords, **p, **q, qc; int on = clwnum, op = clwpos, ois = instring, oib = inbackt; - char *oisuf = isuf, *oqp = qipre, *oqs = qisuf, oaq = autoq; + char *oisuf = isuf, *oqp = qipre, *oqs = qisuf, *oaq = autoq; + char buf[2]; if (compquote && (qc = *compquote)) { if (qc == '`') { instring = 0; inbackt = 0; - autoq = '\0'; + autoq = ""; } else { + buf[0] = qc; + buf[1] = '\0'; instring = (qc == '\'' ? 1 : 2); inbackt = 0; - autoq = qc; + autoq = buf; } } else { instring = inbackt = 0; - autoq = '\0'; + autoq = ""; } qipre = ztrdup(compqiprefix ? compqiprefix : ""); qisuf = ztrdup(compqisuffix ? compqisuffix : ""); @@ -2593,9 +2600,10 @@ sep_comp_string(char *ss, char *s, int noffs) LinkList foo = newlinklist(); LinkNode n; int owe = we, owb = wb, ocs = cs, swb, swe, scs, soffs, ne = noerrs; - int sl = strlen(ss), tl, got = 0, i = 0, cur = -1, oll = ll; + int sl = strlen(ss), tl, got = 0, i = 0, cur = -1, oll = ll, remq; int ois = instring, oib = inbackt; - char *tmp, *p, *ns, *ol = (char *) line, sav, oaq = autoq, *qp, *qs; + char *tmp, *p, *ns, *ol = (char *) line, sav, *oaq = autoq, *qp, *qs; + char *ts, qc = '\0'; swb = swe = soffs = 0; ns = NULL; @@ -2612,6 +2620,8 @@ sep_comp_string(char *ss, char *s, int noffs) memcpy(tmp + sl + 1, s, noffs); tmp[(scs = cs = sl + 1 + noffs)] = 'x'; strcpy(tmp + sl + 2 + noffs, s + noffs); + if ((remq = (*compqstack == '\\'))) + tmp = rembslash(tmp); inpush(dupstrspace(tmp), 0, NULL); line = (unsigned char *) tmp; ll = tl - 1; @@ -2674,21 +2684,29 @@ sep_comp_string(char *ss, char *s, int noffs) *p = '\''; } offs = owb; + + untokenize(ts = dupstring(ns)); + if (*ns == Snull || *ns == Dnull) { instring = (*ns == Snull ? 1 : 2); inbackt = 0; swb++; if (ns[strlen(ns) - 1] == *ns && ns[1]) swe--; - autoq = (*ns == Snull ? '\'' : '"'); + autoq = compqstack[1] ? "" : multiquote(*ns == Snull ? "'" : "\"", 1); + qc = (*ns == Snull ? '\'' : '"'); + ts++; } else { instring = 0; - autoq = '\0'; + autoq = ""; } for (p = ns, i = swb; *p; p++, i++) { if (INULL(*p)) { - if (i < scs) + if (i < scs) { soffs--; + if (remq && *p == Bnull && p[1]) + swb -= 2; + } if (p[1] || *p != Bnull) { if (*p == Bnull) { if (scs == i + 1) @@ -2704,27 +2722,42 @@ sep_comp_string(char *ss, char *s, int noffs) chuck(p--); } } + ns = ts; + + if (instring && strchr(compqstack, '\\')) { + int rl = strlen(ns), ql = strlen(multiquote(ns, !!compqstack[1])); + + if (ql > rl) + swb -= ql - rl; + } sav = s[(i = swb - sl - 1)]; s[i] = '\0'; - qp = tricat(qipre, s, ""); + qp = tricat(qipre, multiquote(s, 0), ""); s[i] = sav; if (swe < swb) swe = swb; swe -= sl + 1; sl = strlen(s); - if (swe > sl) - swe = sl, ns[swe - swb + 1] = '\0'; - qs = tricat(s + swe, qisuf, ""); + if (swe > sl) { + swe = sl; + if (strlen(ns) > swe - swb + 1) + ns[swe - swb + 1] = '\0'; + } + qs = tricat(multiquote(s + swe, 0), qisuf, ""); sl = strlen(ns); if (soffs > sl) soffs = sl; { char **ow = clwords, *os = cmdstr, *oqp = qipre, *oqs = qisuf; + char *oqst = compqstack; int olws = clwsize, olwn = clwnum, olwp = clwpos; int obr = brange, oer = erange, oof = offs; unsigned long occ = ccont; + compqstack = tricat((instring ? (instring == 1 ? "'" : "\"") : "\\"), + compqstack, ""); + clwsize = clwnum = countlinknodes(foo); clwords = (char **) zalloc((clwnum + 1) * sizeof(char *)); for (n = firstnode(foo), i = 0; n; incnode(n), i++) { @@ -2756,6 +2789,8 @@ sep_comp_string(char *ss, char *s, int noffs) qipre = oqp; zsfree(qisuf); qisuf = oqs; + zsfree(compqstack); + compqstack = oqst; } autoq = oaq; instring = ois; diff --git a/Src/Zle/complete.c b/Src/Zle/complete.c index b4d32a34c..bf558f352 100644 --- a/Src/Zle/complete.c +++ b/Src/Zle/complete.c @@ -61,6 +61,7 @@ char **compwords, *compredirect, *compquote, *compquoting, + *compqstack, *comprestore, *complist, *compforcelist, @@ -962,6 +963,7 @@ static struct compparam compkparams[] = { { "vared", PM_SCALAR, VAL(compvared), NULL, NULL }, { "alternate_nmatches", PM_INTEGER | PM_READONLY, NULL, NULL, VAL(get_anmatches) }, { "list_lines", PM_INTEGER | PM_READONLY, NULL, NULL, VAL(get_listlines) }, + { "all_quotes", PM_SCALAR | PM_READONLY, VAL(compqstack), NULL, NULL }, { NULL, 0, NULL, NULL, NULL } }; @@ -1169,7 +1171,7 @@ comp_wrapper(List list, FuncWrap w, char *name) return 1; else { char *orest, *opre, *osuf, *oipre, *oisuf, **owords; - char *oqipre, *oqisuf, *oq, *oqi; + char *oqipre, *oqisuf, *oq, *oqi, *oqs, *oaq; zlong ocur; unsigned int runset = 0, kunset = 0, m, sm; Param *pp; @@ -1193,6 +1195,8 @@ comp_wrapper(List list, FuncWrap w, char *name) oqisuf = dupstring(compqisuffix); oq = dupstring(compquote); oqi = dupstring(compquoting); + oqs = dupstring(compqstack); + oaq = dupstring(autoq); HEAPALLOC { owords = arrdup(compwords); @@ -1218,6 +1222,10 @@ comp_wrapper(List list, FuncWrap w, char *name) compquote = ztrdup(oq); zsfree(compquoting); compquoting = ztrdup(oqi); + zsfree(compqstack); + compqstack = ztrdup(oqs); + zsfree(autoq); + autoq = ztrdup(oaq); freearray(compwords); PERMALLOC { compwords = arrdup(owords); @@ -1354,7 +1362,7 @@ setup_complete(Module m) compquoting = comprestore = complist = compinsert = compexact = compexactstr = comppatmatch = comppatinsert = compforcelist = complastprompt = comptoend = - compoldlist = compoldins = compvared = NULL; + compoldlist = compoldins = compvared = compqstack = NULL; hascompmod = 1; @@ -1418,6 +1426,7 @@ finish_complete(Module m) zsfree(compparameter); zsfree(compredirect); zsfree(compquote); + zsfree(compqstack); zsfree(compquoting); zsfree(comprestore); zsfree(complist); diff --git a/Src/Zle/compmatch.c b/Src/Zle/compmatch.c index 344aef161..c3b4c9eae 100644 --- a/Src/Zle/compmatch.c +++ b/Src/Zle/compmatch.c @@ -33,10 +33,6 @@ #undef GLOBAL_PROTOTYPES #include "compmatch.pro" -/* Convenience macro for calling bslashquote() (formerly quotename()). */ - -#define quotename(s, e) bslashquote(s, e, instring) - /* This compares two cpattern lists and returns non-zero if they are * equal. */ @@ -853,9 +849,8 @@ comp_match(char *pfx, char *sfx, char *w, Patprog cp, Cline *clp, int qu, if (!pattry(cp, r)) return NULL; - r = (qu ? quotename(r, NULL) : dupstring(r)); - if (qu == 2 && r[0] == '\\' && r[1] == '~') - chuck(r); + r = (qu == 2 ? tildequote(r, 0) : multiquote(r, !qu)); + /* We still break it into parts here, trying to build a sensible * cline list for these matches, too. */ w = dupstring(w); @@ -866,10 +861,7 @@ comp_match(char *pfx, char *sfx, char *w, Patprog cp, Cline *clp, int qu, Cline pli, plil; int mpl, rpl, wl; - w = (qu ? quotename(w, NULL) : dupstring(w)); - if (qu == 2 && w[0] == '\\' && w[1] == '~') - chuck(w); - + w = (qu == 2 ? tildequote(w, 0) : multiquote(w, !qu)); wl = strlen(w); /* Always try to match the prefix. */ diff --git a/Src/Zle/compresult.c b/Src/Zle/compresult.c index 5b807684e..b3c8bdd4f 100644 --- a/Src/Zle/compresult.c +++ b/Src/Zle/compresult.c @@ -33,11 +33,6 @@ #undef GLOBAL_PROTOTYPES #include "compresult.pro" -/* Convenience macro for calling bslashquote() (formerly quotename()). * - * This uses the instring variable above. */ - -#define quotename(s, e) bslashquote(s, e, instring) - #define inststr(X) inststrlen((X),1,-1) /* This cuts the cline list before the stuff that isn't worth @@ -857,11 +852,13 @@ do_single(Cmatch m) /* If we didn't add a suffix, add a space, unless we are * * doing menu completion or we are completing files and * * the string doesn't name an existing file. */ - if (m->autoq && (!m->isuf || m->isuf[0] != m->autoq)) { - inststrlen(&(m->autoq), 1, 1); - minfo.insc++; + if (m->autoq && (!m->isuf || !strpfx(m->autoq, m->isuf))) { + int al = strlen(m->autoq); + inststrlen(m->autoq, 1, al); + minfo.insc += al; } - if (!menucmp && (usemenu != 3 || insspace)) { + if (!menucmp && !(m->flags & CMF_NOSPACE) && + (usemenu != 3 || insspace)) { inststrlen(" ", 1, 1); minfo.insc++; if (minfo.we) diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c index 0f8188762..22a8f7656 100644 --- a/Src/Zle/computil.c +++ b/Src/Zle/computil.c @@ -1887,11 +1887,62 @@ bin_compvalues(char *nam, char **args, char *ops, int func) } +static int +bin_compquote(char *nam, char **args, char *ops, int func) +{ + char *name; + Value v; + + if (!compqstack || !*compqstack) + return 0; + + while ((name = *args++)) { + name = dupstring(name); + if ((v = getvalue(&name, 0))) { + switch (PM_TYPE(v->pm->flags)) { + case PM_SCALAR: + { + char *val = getstrvalue(v); + + val = bslashquote(val, NULL, + (*compqstack == '\'' ? 1 : + (*compqstack == '"' ? 2 : 0))); + + setstrvalue(v, ztrdup(val)); + } + break; + case PM_ARRAY: + { + char **val = v->pm->gets.afn(v->pm); + char **new = (char **) zalloc((arrlen(val) + 1) * + sizeof(char *)); + char **p = new; + + for (; *val; val++, p++) + *p = ztrdup(bslashquote(*val, NULL, + (*compqstack == '\'' ? 1 : + (*compqstack == '"' ? 2 : + 0)))); + *p = NULL; + + setarrvalue(v, new); + } + break; + default: + zwarnnam(nam, "invalid parameter type: %s", args[-1], 0); + } + } else + zwarnnam(nam, "unknown parameter: %s", args[-1], 0); + } + return 0; +} + static struct builtin bintab[] = { BUILTIN("compdisplay", 0, bin_compdisplay, 2, -1, 0, NULL, NULL), BUILTIN("compdescribe", 0, bin_compdescribe, 3, -1, 0, NULL, NULL), BUILTIN("comparguments", 0, bin_comparguments, 1, -1, 0, NULL, NULL), BUILTIN("compvalues", 0, bin_compvalues, 1, -1, 0, NULL, NULL), + BUILTIN("compquote", 0, bin_compquote, 1, -1, 0, NULL, NULL), }; diff --git a/Src/Zle/computil.mdd b/Src/Zle/computil.mdd index 56f633414..4789280a9 100644 --- a/Src/Zle/computil.mdd +++ b/Src/Zle/computil.mdd @@ -2,4 +2,4 @@ moddeps="complete" objects="computil.o" -autobins="compdisplay compdescribe comparguments compvalues" +autobins="compdisplay compdescribe comparguments compvalues compquote" diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c index 6a17c46d0..04b841411 100644 --- a/Src/Zle/zle_tricky.c +++ b/Src/Zle/zle_tricky.c @@ -112,7 +112,7 @@ static char *qword; * closing quote. */ /**/ -char *qipre, *qisuf, autoq; +char *qipre, *qisuf, *autoq; /* This contains the name of the function to call if this is for a new * * style completion. */ @@ -547,7 +547,8 @@ docomplete(int lst) qipre = ztrdup(""); zsfree(qisuf); qisuf = ztrdup(""); - autoq = '\0'; + zsfree(autoq); + autoq = NULL; /* Get the word to complete. */ noerrs = 1; s = get_comp_string(); @@ -882,6 +883,20 @@ dupbrinfo(Brinfo p, Brinfo *last) return ret; } +/* This is a bit like has_token(), but ignores nulls. */ + +static int +has_real_token(const char *s) +{ + while (*s) { + if (itok(*s) && !INULL(*s)) + return 1; + s++; + } + return 0; +} + + /* Lasciate ogni speranza. * * This function is a nightmare. It works, but I'm sure that nobody really * * understands why. The problem is: to make it cleaner we would need * @@ -1264,7 +1279,7 @@ get_comp_string(void) else if (*p == Snull) *p = '\''; } - if ((*s == Snull || *s == Dnull) && !has_token(s + 1)) { + if ((*s == Snull || *s == Dnull) && !has_real_token(s + 1)) { char *q = (*s == Snull ? "'" : "\""), *n = tricat(qipre, q, ""); int sl = strlen(s); @@ -1276,7 +1291,7 @@ get_comp_string(void) zsfree(qisuf); qisuf = n; } - autoq = *q; + autoq = ztrdup(q); } /* While building the quoted form, we also clean up the command line. */ for (p = s, tt = qword, i = wb; *p; p++, tt++, i++) diff --git a/Src/params.c b/Src/params.c index 4c4f89978..b41ef6b37 100644 --- a/Src/params.c +++ b/Src/params.c @@ -1417,7 +1417,7 @@ getnumvalue(Value v) } /**/ -static void +void setstrvalue(Value v, char *val) { char buf[(sizeof(zlong) * 8) + 4]; @@ -1515,7 +1515,7 @@ setstrvalue(Value v, char *val) } /**/ -static void +void setnumvalue(Value v, mnumber val) { char buf[DIGBUFSIZE], *p; @@ -1552,7 +1552,7 @@ setnumvalue(Value v, mnumber val) } /**/ -static void +void setarrvalue(Value v, char **val) { if (v->pm->flags & PM_READONLY) { -- cgit 1.4.1