diff options
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | Doc/Zsh/compwid.yo | 15 | ||||
-rw-r--r-- | Doc/Zsh/contrib.yo | 14 | ||||
-rw-r--r-- | Functions/Zle/cycle-completion-positions | 16 | ||||
-rw-r--r-- | Src/Zle/comp.h | 26 | ||||
-rw-r--r-- | Src/Zle/complete.c | 30 | ||||
-rw-r--r-- | Src/Zle/compresult.c | 124 |
7 files changed, 196 insertions, 37 deletions
diff --git a/ChangeLog b/ChangeLog index 80fa9a08c..0ee03ea35 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2001-01-11 Sven Wischnowsky <wischnow@zsh.org> + + * 13339: Doc/Zsh/compwid.yo, Doc/Zsh/contrib.yo, + Functions/Zle/cycle-completion-positions, Src/Zle/comp.h, + Src/Zle/complete.c, Src/Zle/compresult.c: add + unambiguous_positions and insert_positions keys to $compstate; use + them in the new cycle-completion-positions shell function widget + 2001-01-10 Geoff Wing <gcw@zsh.org> * unposted: Etc/MACHINES: format leading spaces to tabs diff --git a/Doc/Zsh/compwid.yo b/Doc/Zsh/compwid.yo index e793085af..88da670b6 100644 --- a/Doc/Zsh/compwid.yo +++ b/Doc/Zsh/compwid.yo @@ -240,6 +240,14 @@ matches generated be ignored and only the TAB be inserted. Finally, it may also be set to tt(all), which makes all matches generated be inserted into the line. ) +vindex(insert_positions, compstate) +item(tt(insert_positions))( +When the completion system inserts an unambiguous string into the +line, there may be multiple places where characters are missing or +where the character inserted differs from at least one match. The +value of this key contains a colon separated list of all these +positions, as indexes into the command line. +) vindex(last_prompt, compstate) item(tt(last_prompt))( If this is set to an non-empty string for every match added, the @@ -397,6 +405,13 @@ common prefix in the tt(unambiguous) key were inserted, relative to the value of that key. The cursor would be placed before the character whose index is given by this key. ) +vindex(unambiguous_positions, compstate) +item(tt(unambiguous_positions))( +This contains all positions where characters in the unambiguous string +are missing or where the character inserted differs from at least one +of the matches. The positions are given as indexes into the string +given by the value of the tt(uanmbiguous) key. +) vindex(vared, compstate) item(tt(vared))( If completion is called while editing a line using the tt(vared) diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo index eb5f202da..77abc97a0 100644 --- a/Doc/Zsh/contrib.yo +++ b/Doc/Zsh/contrib.yo @@ -316,6 +316,20 @@ followed by an appropriate tt(bindkey) command to associate the function with a key sequence. Suggested bindings are described below. startitem() +tindex(cycle-completion-positions) +item(tt(cycle-completion-positions))( +After inserting an unambiguous string into the command line, the new +function based completion system may know about multiple places in +this string where characters are missing or differ from at least one +of the possible matches. It will then place the cursor on the +position it considers to be the most interesting one, i.e. the one +where one can disambiguate between as many matches as possible with as +little typing as possible. + +This widget allows to easily move the cursor to the other interesting +spots. It can be invoked repeatedly to cycle between all positions +reported by the completion system. +) tindex(edit-command-line) item(tt(edit-command-line))( Edit the command line using your visual editor, as in tt(ksh). diff --git a/Functions/Zle/cycle-completion-positions b/Functions/Zle/cycle-completion-positions new file mode 100644 index 000000000..34a2d8174 --- /dev/null +++ b/Functions/Zle/cycle-completion-positions @@ -0,0 +1,16 @@ +# This may be called after a completion that inserted the unambiguous +# (i.e. non-menu- and non-single-match-) string into the command line. +# If there are multiple positions in the string with missing or differing +# characters, repeatedly calling this widget cycles between all these +# positions. + +emulate -L zsh +setopt extendedglob + +local p="$_lastcomp[insert_positions]" + +if [[ $p = ((#s)|*:)${CURSOR}:* ]]; then + CURSOR=${${p#(|*:)${CURSOR}:}%%:*} +elif [[ -n $p ]]; then + CURSOR=${p%%:*} +fi diff --git a/Src/Zle/comp.h b/Src/Zle/comp.h index b18947064..22029d511 100644 --- a/Src/Zle/comp.h +++ b/Src/Zle/comp.h @@ -345,27 +345,31 @@ typedef void (*CLPrintFunc)(Cmgroup, Cmatch *, int, int, int, int, #define CP_UNAMBIG (1 << CPN_UNAMBIG) #define CPN_UNAMBIGC 14 #define CP_UNAMBIGC (1 << CPN_UNAMBIGC) -#define CPN_LISTMAX 15 +#define CPN_UNAMBIGP 15 +#define CP_UNAMBIGP (1 << CPN_UNAMBIGP) +#define CPN_INSERTP 16 +#define CP_INSERTP (1 << CPN_INSERTP) +#define CPN_LISTMAX 17 #define CP_LISTMAX (1 << CPN_LISTMAX) -#define CPN_LASTPROMPT 16 +#define CPN_LASTPROMPT 18 #define CP_LASTPROMPT (1 << CPN_LASTPROMPT) -#define CPN_TOEND 17 +#define CPN_TOEND 19 #define CP_TOEND (1 << CPN_TOEND) -#define CPN_OLDLIST 18 +#define CPN_OLDLIST 20 #define CP_OLDLIST (1 << CPN_OLDLIST) -#define CPN_OLDINS 19 +#define CPN_OLDINS 21 #define CP_OLDINS (1 << CPN_OLDINS) -#define CPN_VARED 20 +#define CPN_VARED 22 #define CP_VARED (1 << CPN_VARED) -#define CPN_LISTLINES 21 +#define CPN_LISTLINES 23 #define CP_LISTLINES (1 << CPN_LISTLINES) -#define CPN_QUOTES 22 +#define CPN_QUOTES 24 #define CP_QUOTES (1 << CPN_QUOTES) -#define CPN_IGNORED 23 +#define CPN_IGNORED 25 #define CP_IGNORED (1 << CPN_IGNORED) -#define CP_KEYPARAMS 24 -#define CP_ALLKEYS ((unsigned int) 0xffffff) +#define CP_KEYPARAMS 26 +#define CP_ALLKEYS ((unsigned int) 0x3ffffff) /* Hooks. */ diff --git a/Src/Zle/complete.c b/Src/Zle/complete.c index df9faed7a..5c166291e 100644 --- a/Src/Zle/complete.c +++ b/Src/Zle/complete.c @@ -956,6 +956,10 @@ static struct compparam compkparams[] = { { "unambiguous", PM_SCALAR | PM_READONLY, NULL, NULL, VAL(get_unambig) }, { "unambiguous_cursor", PM_INTEGER | PM_READONLY, NULL, NULL, VAL(get_unambig_curs) }, + { "unambiguous_positions", PM_SCALAR | PM_READONLY, NULL, NULL, + VAL(get_unambig_pos) }, + { "insert_positions", PM_SCALAR | PM_READONLY, NULL, NULL, + VAL(get_insert_pos) }, { "list_max", PM_INTEGER, VAL(complistmax), NULL, NULL }, { "last_prompt", PM_SCALAR, VAL(complastprompt), NULL, NULL }, { "to_end", PM_SCALAR, VAL(comptoend), NULL, NULL }, @@ -1103,7 +1107,7 @@ get_complist(Param pm) static char * get_unambig(Param pm) { - return unambig_data(NULL); + return unambig_data(NULL, NULL, NULL); } /**/ @@ -1112,12 +1116,34 @@ get_unambig_curs(Param pm) { int c; - unambig_data(&c); + unambig_data(&c, NULL, NULL); return c; } /**/ +static char * +get_unambig_pos(Param pm) +{ + char *p; + + unambig_data(NULL, &p, NULL); + + return p; +} + +/**/ +static char * +get_insert_pos(Param pm) +{ + char *p; + + unambig_data(NULL, NULL, &p); + + return p; +} + +/**/ static void compunsetfn(Param pm, int exp) { diff --git a/Src/Zle/compresult.c b/Src/Zle/compresult.c index 287e1509f..061c2a6fd 100644 --- a/Src/Zle/compresult.c +++ b/Src/Zle/compresult.c @@ -154,18 +154,20 @@ cut_cline(Cline l) return l; } -/* This builds the unambiguous string. If ins is non-zero, it is - * immediatly inserted in the line. Otherwise csp is used to return - * the relative cursor position in the string returned. */ +/* This builds the unambiguous string. If ins is one, it is immediately + * inserted into the line. Otherwise csp is used to return the relative + * cursor position in the string returned and posl contains all + * positions with missing or ambiguous characters. If ins is two, csp + * and posl contain real command line positions (including braces). */ /**/ static char * -cline_str(Cline l, int ins, int *csp) +cline_str(Cline l, int ins, int *csp, LinkList posl) { Cline s; int ocs = cs, ncs, pcs, scs; int pm, pmax, pmm, pma, sm, smax, smm, sma, d, dm, mid; - int i, j, li = 0, cbr; + int i, j, li = 0, cbr, padd = (ins ? wb - ocs : -ocs); Brinfo brp, brs; l = cut_cline(l); @@ -222,6 +224,8 @@ cline_str(Cline l, int ins, int *csp) if ((s->flags & CLF_DIFF) && (!dm || (s->flags & CLF_MATCHED))) { d = cs; dm = s->flags & CLF_MATCHED; + if (posl) + addlinknode(posl, (void *) ((long) (cs + padd))); } li += s->llen; } @@ -242,12 +246,15 @@ cline_str(Cline l, int ins, int *csp) } /* Remember the position if this is the first prefix with * missing characters. */ - if ((l->flags & CLF_MISS) && !(l->flags & CLF_SUF) && - (((pmax < (l->max - l->min) || (pma && l->max != l->min)) && - (!pmm || (l->flags & CLF_MATCHED))) || - ((l->flags & CLF_MATCHED) && !pmm))) { - pm = cs; pmax = l->max - l->min; pmm = l->flags & CLF_MATCHED; - pma = ((l->prefix || l->suffix) && l->min == cline_sublen(l)); + if ((l->flags & CLF_MISS) && !(l->flags & CLF_SUF)) { + if (posl && l->min != l->max) + addlinknode(posl, (void *) ((long) (cs + padd))); + if (((pmax < (l->max - l->min) || (pma && l->max != l->min)) && + (!pmm || (l->flags & CLF_MATCHED))) || + ((l->flags & CLF_MATCHED) && !pmm)) { + pm = cs; pmax = l->max - l->min; pmm = l->flags & CLF_MATCHED; + pma = ((l->prefix || l->suffix) && l->min == cline_sublen(l)); + } } if (ins) { int ocs, bl; @@ -291,12 +298,15 @@ cline_str(Cline l, int ins, int *csp) if (l->flags & CLF_MISS) { if (l->flags & CLF_MID) mid = cs; - else if ((l->flags & CLF_SUF) && - (((smax < (l->min - l->max) || (sma && l->max != l->min)) && - (!smm || (l->flags & CLF_MATCHED))) || - ((l->flags & CLF_MATCHED) && !smm))) { - sm = cs; smax = l->min - l->max; smm = l->flags & CLF_MATCHED; - sma = ((l->prefix || l->suffix) && l->min == cline_sublen(l)); + else if (l->flags & CLF_SUF) { + if (posl && l->min != l->max) + addlinknode(posl, (void *) ((long) (cs + padd))); + if (((smax < (l->min - l->max) || (sma && l->max != l->min)) && + (!smm || (l->flags & CLF_MATCHED))) || + ((l->flags & CLF_MATCHED) && !smm)) { + sm = cs; smax = l->min - l->max; smm = l->flags & CLF_MATCHED; + sma = ((l->prefix || l->suffix) && l->min == cline_sublen(l)); + } } } if (ins) { @@ -389,10 +399,14 @@ cline_str(Cline l, int ins, int *csp) cs += i; if (j >= 0 && (!dm || (js->flags & CLF_MATCHED))) { d = cs - j; dm = js->flags & CLF_MATCHED; + if (posl) + addlinknode(posl, (void *) ((long) (cs - j + padd))); } } l = l->next; } + if (posl) + addlinknode(posl, (void *) ((long) (cs + padd))); if (ins) { int ocs = cs; @@ -411,6 +425,17 @@ cline_str(Cline l, int ins, int *csp) sm += cs - ocs; if (d >= ocs) d += cs - ocs; + + if (posl) { + LinkNode node; + long p; + + for (node = firstnode(posl); node; incnode(node)) { + p = (long) getdata(node); + if (p >= ocs) + setdata(node, (void *) (p + cs - ocs)); + } + } } /* This calculates the new cursor position. If we had a mid cline * with missing characters, we take this, otherwise if we have a @@ -420,7 +445,7 @@ cline_str(Cline l, int ins, int *csp) (cbr >= 0 ? cbr : (pm >= 0 ? pm : (sm >= 0 ? sm : (d >= 0 ? d : cs))))); - if (!ins) { + if (ins != 1) { /* We always inserted the string in the line. If that was not * requested, we copy it and remove from the line. */ char *r = zalloc((i = cs - ocs) + 1); @@ -430,7 +455,8 @@ cline_str(Cline l, int ins, int *csp) cs = ocs; foredel(i); - *csp = ncs - ocs; + if (csp) + *csp = ncs - ocs; return r; } @@ -440,31 +466,81 @@ cline_str(Cline l, int ins, int *csp) return NULL; } +/* Small utility function turning a list of positions into a colon + * separated string. */ + +static char * +build_pos_string(LinkList list) +{ + LinkNode node; + int l; + char buf[40], *s; + + for (node = firstnode(list), l = 0; node; incnode(node)) { + sprintf(buf, "%ld", (long) getdata(node)); + setdata(node, dupstring(buf)); + l += 1 + strlen(buf); + } + s = (char *) zalloc(l * sizeof(char)); + *s = 0; + for (node = firstnode(list); node;) { + strcat(s, (char *) getdata(node)); + incnode(node); + if (node) + strcat(s, ":"); + } + return s; +} + /* This is a utility function using the function above to allow access * to the unambiguous string and cursor position via compstate. */ /**/ char * -unambig_data(int *cp) +unambig_data(int *cp, char **pp, char **ip) { - static char *scache = NULL; + static char *scache = NULL, *pcache = NULL, *icache = NULL; static int ccache; if (mnum && ainfo) { if (mnum != unambig_mnum) { + LinkList list = newlinklist(); + zsfree(scache); scache = cline_str((ainfo->count ? ainfo->line : fainfo->line), - 0, &ccache); + 0, &ccache, list); + zsfree(pcache); + if (empty(list)) + pcache = ztrdup(""); + else + pcache = build_pos_string(list); + + zsfree(icache); + + list = newlinklist(); + zsfree(cline_str((ainfo->count ? ainfo->line : fainfo->line), + 2, NULL, list)); + if (empty(list)) + icache = ztrdup(""); + else + icache = build_pos_string(list); } } else if (mnum != unambig_mnum || !ainfo || !scache) { zsfree(scache); scache = ztrdup(""); + zsfree(pcache); + pcache = ztrdup(""); + zsfree(icache); + icache = ztrdup(""); ccache = 0; } unambig_mnum = mnum; if (cp) *cp = ccache + 1; - + if (pp) + *pp = pcache; + if (ip) + *ip = icache; return scache; } @@ -665,7 +741,7 @@ do_ambiguous(void) foredel(we - wb); /* Now get the unambiguous string and insert it into the line. */ - cline_str(ainfo->line, 1, NULL); + cline_str(ainfo->line, 1, NULL, NULL); /* Sometimes the different match specs used may result in a cline * that gives an empty string. If that happened, we re-insert the |