1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-31 01:20:37 -08:00

(Ftry_completion, Fall_completions, Ftest_completion):

Add support for hash-tables.
(Ftry_completion): Return t even if the string appears multiple times.
This commit is contained in:
Stefan Monnier 2002-07-07 21:09:14 +00:00
parent b143237987
commit 85cd4372bc

View file

@ -1089,8 +1089,9 @@ common to all matches is returned as a string.
If there is no match at all, nil is returned.
For a unique match which is exact, t is returned.
ALIST can be an obarray instead of an alist.
Then the print names of all symbols in the obarray are the possible matches.
If ALIST is a hash-table, all the string keys are the possible matches.
If ALIST is an obarray, the names of all symbols in the obarray
are the possible matches.
ALIST can also be a function to do the completion itself.
It receives three arguments: the values STRING, PREDICATE and nil.
@ -1100,7 +1101,8 @@ If optional third argument PREDICATE is non-nil,
it is used to test each possible match.
The match is a candidate only if PREDICATE returns non-nil.
The argument given to PREDICATE is the alist element
or the symbol from the obarray.
or the symbol from the obarray. If ALIST is a hash-table,
predicate is called with two arguments: the key and the value.
Additionally to this predicate, `completion-regexp-list'
is used to further constrain the set of candidates. */)
(string, alist, predicate)
@ -1111,37 +1113,38 @@ is used to further constrain the set of candidates. */)
int bestmatchsize = 0;
/* These are in bytes, too. */
int compare, matchsize;
int list = NILP (alist) || (CONSP (alist)
&& (!SYMBOLP (XCAR (alist))
|| NILP (XCAR (alist))));
int type = HASH_TABLE_P (alist) ? 3
: VECTORP (alist) ? 2
: NILP (alist) || (CONSP (alist)
&& (!SYMBOLP (XCAR (alist))
|| NILP (XCAR (alist))));
int index = 0, obsize = 0;
int matchcount = 0;
Lisp_Object bucket, zero, end, tem;
struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
CHECK_STRING (string);
if (!list && !VECTORP (alist))
if (type == 0)
return call3 (alist, string, predicate, Qnil);
bestmatch = bucket = Qnil;
/* If ALIST is not a list, set TAIL just for gc pro. */
tail = alist;
if (! list)
if (type == 2)
{
index = 0;
obsize = XVECTOR (alist)->size;
bucket = XVECTOR (alist)->contents[index];
}
while (1)
{
/* Get the next element of the alist or obarray. */
/* Get the next element of the alist, obarray, or hash-table. */
/* Exit the loop if the elements are all used up. */
/* elt gets the alist element or symbol.
eltstring gets the name to check as a completion. */
if (list)
if (type == 1)
{
if (!CONSP (tail))
break;
@ -1149,7 +1152,7 @@ is used to further constrain the set of candidates. */)
eltstring = CONSP (elt) ? XCAR (elt) : elt;
tail = XCDR (tail);
}
else
else if (type == 2)
{
if (XFASTINT (bucket) != 0)
{
@ -1168,6 +1171,16 @@ is used to further constrain the set of candidates. */)
continue;
}
}
else /* if (type == 3) */
{
while (index < HASH_TABLE_SIZE (XHASH_TABLE (alist))
&& NILP (HASH_HASH (XHASH_TABLE (alist), index)))
index++;
if (index >= HASH_TABLE_SIZE (XHASH_TABLE (alist)))
break;
else
elt = eltstring = HASH_KEY (XHASH_TABLE (alist), index++);
}
/* Is this element a possible completion? */
@ -1205,7 +1218,10 @@ is used to further constrain the set of candidates. */)
else
{
GCPRO4 (tail, string, eltstring, bestmatch);
tem = call1 (predicate, elt);
tem = type == 3
? call2 (predicate, elt,
HASH_VALUE (XHASH_TABLE (alist), index - 1))
: call1 (predicate, elt);
UNGCPRO;
}
if (NILP (tem)) continue;
@ -1213,9 +1229,9 @@ is used to further constrain the set of candidates. */)
/* Update computation of how much all possible completions match */
matchcount++;
if (NILP (bestmatch))
{
matchcount = 1;
bestmatch = eltstring;
bestmatchsize = XSTRING (eltstring)->size;
}
@ -1269,6 +1285,10 @@ is used to further constrain the set of candidates. */)
! EQ (Qt, tem))))
bestmatch = eltstring;
}
if (bestmatchsize != XSTRING (eltstring)->size
|| bestmatchsize != matchsize)
/* Don't count the same string multiple times. */
matchcount++;
bestmatchsize = matchsize;
if (matchsize <= XSTRING (string)->size
&& matchcount > 1)
@ -1308,8 +1328,9 @@ DEFUN ("all-completions", Fall_completions, Sall_completions, 2, 4, 0,
Each car of each element of ALIST is tested to see if it begins with STRING.
The value is a list of all the strings from ALIST that match.
ALIST can be an obarray instead of an alist.
Then the print names of all symbols in the obarray are the possible matches.
If ALIST is a hash-table, all the string keys are the possible matches.
If ALIST is an obarray, the names of all symbols in the obarray
are the possible matches.
ALIST can also be a function to do the completion itself.
It receives three arguments: the values STRING, PREDICATE and t.
@ -1319,7 +1340,8 @@ If optional third argument PREDICATE is non-nil,
it is used to test each possible match.
The match is a candidate only if PREDICATE returns non-nil.
The argument given to PREDICATE is the alist element
or the symbol from the obarray.
or the symbol from the obarray. If ALIST is a hash-table,
predicate is called with two arguments: the key and the value.
Additionally to this predicate, `completion-regexp-list'
is used to further constrain the set of candidates.
@ -1331,37 +1353,36 @@ are ignored unless STRING itself starts with a space. */)
{
Lisp_Object tail, elt, eltstring;
Lisp_Object allmatches;
int list = NILP (alist) || (CONSP (alist)
&& (!SYMBOLP (XCAR (alist))
|| NILP (XCAR (alist))));
int type = HASH_TABLE_P (alist) ? 3
: VECTORP (alist) ? 2
: NILP (alist) || (CONSP (alist)
&& (!SYMBOLP (XCAR (alist))
|| NILP (XCAR (alist))));
int index = 0, obsize = 0;
Lisp_Object bucket, tem;
struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
CHECK_STRING (string);
if (!list && !VECTORP (alist))
{
return call3 (alist, string, predicate, Qt);
}
if (type == 0)
return call3 (alist, string, predicate, Qt);
allmatches = bucket = Qnil;
/* If ALIST is not a list, set TAIL just for gc pro. */
tail = alist;
if (! list)
if (type == 2)
{
index = 0;
obsize = XVECTOR (alist)->size;
bucket = XVECTOR (alist)->contents[index];
}
while (1)
{
/* Get the next element of the alist or obarray. */
/* Get the next element of the alist, obarray, or hash-table. */
/* Exit the loop if the elements are all used up. */
/* elt gets the alist element or symbol.
eltstring gets the name to check as a completion. */
if (list)
if (type == 1)
{
if (!CONSP (tail))
break;
@ -1369,7 +1390,7 @@ are ignored unless STRING itself starts with a space. */)
eltstring = CONSP (elt) ? XCAR (elt) : elt;
tail = XCDR (tail);
}
else
else if (type == 2)
{
if (XFASTINT (bucket) != 0)
{
@ -1388,6 +1409,16 @@ are ignored unless STRING itself starts with a space. */)
continue;
}
}
else /* if (type == 3) */
{
while (index < HASH_TABLE_SIZE (XHASH_TABLE (alist))
&& NILP (HASH_HASH (XHASH_TABLE (alist), index)))
index++;
if (index >= HASH_TABLE_SIZE (XHASH_TABLE (alist)))
break;
else
elt = eltstring = HASH_KEY (XHASH_TABLE (alist), index++);
}
/* Is this element a possible completion? */
@ -1432,7 +1463,10 @@ are ignored unless STRING itself starts with a space. */)
else
{
GCPRO4 (tail, eltstring, allmatches, string);
tem = call1 (predicate, elt);
tem = type == 3
? call2 (predicate, elt,
HASH_VALUE (XHASH_TABLE (alist), index - 1))
: call1 (predicate, elt);
UNGCPRO;
}
if (NILP (tem)) continue;
@ -1564,6 +1598,7 @@ the values STRING, PREDICATE and `lambda'. */)
Lisp_Object string, alist, predicate;
{
Lisp_Object regexps, tem = Qnil;
int i = 0;
CHECK_STRING (string);
@ -1571,9 +1606,7 @@ the values STRING, PREDICATE and `lambda'. */)
|| NILP (alist))
{
tem = Fassoc_string (string, alist, completion_ignore_case ? Qt : Qnil);
if (CONSP (tem))
tem = XCAR (tem);
else
if NILP (tem)
return Qnil;
}
else if (VECTORP (alist))
@ -1598,6 +1631,14 @@ the values STRING, PREDICATE and `lambda'. */)
return Qnil;
}
}
else if (HASH_TABLE_P (alist))
{
i = hash_lookup (XHASH_TABLE (alist), string, NULL);
if (i >= 0)
tem = HASH_KEY (XHASH_TABLE (alist), i);
else
return Qnil;
}
else
return call3 (alist, string, predicate, Qlambda);
@ -1613,7 +1654,9 @@ the values STRING, PREDICATE and `lambda'. */)
/* Finally, check the predicate. */
if (!NILP (predicate))
return call1 (predicate, tem);
return HASH_TABLE_P (alist)
? call2 (predicate, tem, HASH_VALUE (XHASH_TABLE (alist), i))
: call1 (predicate, tem);
else
return Qt;
}