Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
Re: Bug w/matching control + feature request
- X-seq: zsh-workers 13339
- From: Sven Wischnowsky <wischnow@xxxxxxxxxxxxxxxxxxxxxxx>
- To: zsh-workers@xxxxxxxxxxxxxx
- Subject: Re: Bug w/matching control + feature request
- Date: Thu, 11 Jan 2001 10:56:58 +0100 (MET)
- In-reply-to: Felix Rosencrantz's message of Sat, 30 Dec 2000 14:58:58 -0800 (PST)
- Mailing-list: contact zsh-workers-help@xxxxxxxxxx; run by ezmlm
Felix Rosencrantz wrote:
> Hmm... Since the matching specs and cursor positioning came up again,
> it got me thinking about a feature request I've wanted. There are times
> when matching places the cursor at the undesired spot for finishing the
> completion of the word I'm completing. The matching code has an idea of
> where several other reasonable cursor positions are (see the code
> at zsh/Src/Zle/compresult.c:415, which picks from several possible
> cursor locations as hot spots, there are probably a few more.)
>
> It seems like there would need to be a global array that is accessible to the
> completion functions, that would hold valid hot spots in the current word.
> It would then be possible to write a widget that would cycle the cursor
> between these spots.
Here is the patch. It adds two new $compstate-keys:
`unambiguous_positions' and `insert_positions'. Both give the
interesting positions as colon separated lists. The former reports
them relative to $compstate[unambiguous] and the latter relative to
the command line (i.e. usable as $CURSOR values). The distinction is
important, because $compstate[unambiguous] doesn't contain the braces,
if any, so the positions may be completely different in the two lists.
The patch also add the widget function `cycle-completion-positions'
which can be invoked repeatedly to cycle between the interesting spots.
Hm, the patch looks bigger than it is. And because it is only an
add-on and shouldn't be able to break anything, I'll commit it right
away.
Bye
Sven
Index: Doc/Zsh/compwid.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/compwid.yo,v
retrieving revision 1.27
diff -u -r1.27 compwid.yo
--- Doc/Zsh/compwid.yo 2000/10/11 12:19:25 1.27
+++ Doc/Zsh/compwid.yo 2001/01/11 09:53:12
@@ -240,6 +240,14 @@
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
@@ -396,6 +404,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))(
Index: Doc/Zsh/contrib.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/contrib.yo,v
retrieving revision 1.7
diff -u -r1.7 contrib.yo
--- Doc/Zsh/contrib.yo 2000/09/20 06:33:30 1.7
+++ Doc/Zsh/contrib.yo 2001/01/11 09:53:12
@@ -316,6 +316,20 @@
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).
Index: Functions/Zle/cycle-completion-positions
===================================================================
RCS file: cycle-completion-positions
diff -N cycle-completion-positions
--- /dev/null Mon Dec 11 17:26:27 2000
+++ cycle-completion-positions Thu Jan 11 01:53:12 2001
@@ -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
Index: Src/Zle/comp.h
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/comp.h,v
retrieving revision 1.9
diff -u -r1.9 comp.h
--- Src/Zle/comp.h 2000/10/11 12:19:25 1.9
+++ Src/Zle/comp.h 2001/01/11 09:53:13
@@ -345,27 +345,31 @@
#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. */
Index: Src/Zle/complete.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/complete.c,v
retrieving revision 1.14
diff -u -r1.14 complete.c
--- Src/Zle/complete.c 2000/10/11 12:19:25 1.14
+++ Src/Zle/complete.c 2001/01/11 09:53:13
@@ -956,6 +956,10 @@
{ "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 @@
static char *
get_unambig(Param pm)
{
- return unambig_data(NULL);
+ return unambig_data(NULL, NULL, NULL);
}
/**/
@@ -1112,9 +1116,31 @@
{
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;
}
/**/
Index: Src/Zle/compresult.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/compresult.c,v
retrieving revision 1.29
diff -u -r1.29 compresult.c
--- Src/Zle/compresult.c 2001/01/10 09:24:46 1.29
+++ Src/Zle/compresult.c 2001/01/11 09:53:14
@@ -154,18 +154,20 @@
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 @@
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 @@
}
/* 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 @@
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 @@
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 @@
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 @@
(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 @@
cs = ocs;
foredel(i);
- *csp = ncs - ocs;
+ if (csp)
+ *csp = ncs - ocs;
return r;
}
@@ -440,31 +466,81 @@
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 @@
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
--
Sven Wischnowsky wischnow@xxxxxxxxxxxxxxxxxxxxxxx
Messages sorted by:
Reverse Date,
Date,
Thread,
Author