diff options
| author | Stefan Monnier | 2002-07-07 21:09:14 +0000 |
|---|---|---|
| committer | Stefan Monnier | 2002-07-07 21:09:14 +0000 |
| commit | 85cd4372bcaf22d8f12116bd01ed332bc867902b (patch) | |
| tree | cf3cddde054487dafc38528dbc6e28b24ed42548 | |
| parent | b14323798719688ea2725a9b80e8e6e4d9139b6e (diff) | |
| download | emacs-85cd4372bcaf22d8f12116bd01ed332bc867902b.tar.gz emacs-85cd4372bcaf22d8f12116bd01ed332bc867902b.zip | |
(Ftry_completion, Fall_completions, Ftest_completion):
Add support for hash-tables.
(Ftry_completion): Return t even if the string appears multiple times.
| -rw-r--r-- | src/minibuf.c | 111 |
1 files changed, 77 insertions, 34 deletions
diff --git a/src/minibuf.c b/src/minibuf.c index f4aeb0f8c38..87fc6f8ce4a 100644 --- a/src/minibuf.c +++ b/src/minibuf.c | |||
| @@ -1089,8 +1089,9 @@ common to all matches is returned as a string. | |||
| 1089 | If there is no match at all, nil is returned. | 1089 | If there is no match at all, nil is returned. |
| 1090 | For a unique match which is exact, t is returned. | 1090 | For a unique match which is exact, t is returned. |
| 1091 | 1091 | ||
| 1092 | ALIST can be an obarray instead of an alist. | 1092 | If ALIST is a hash-table, all the string keys are the possible matches. |
| 1093 | Then the print names of all symbols in the obarray are the possible matches. | 1093 | If ALIST is an obarray, the names of all symbols in the obarray |
| 1094 | are the possible matches. | ||
| 1094 | 1095 | ||
| 1095 | ALIST can also be a function to do the completion itself. | 1096 | ALIST can also be a function to do the completion itself. |
| 1096 | It receives three arguments: the values STRING, PREDICATE and nil. | 1097 | It receives three arguments: the values STRING, PREDICATE and nil. |
| @@ -1100,7 +1101,8 @@ If optional third argument PREDICATE is non-nil, | |||
| 1100 | it is used to test each possible match. | 1101 | it is used to test each possible match. |
| 1101 | The match is a candidate only if PREDICATE returns non-nil. | 1102 | The match is a candidate only if PREDICATE returns non-nil. |
| 1102 | The argument given to PREDICATE is the alist element | 1103 | The argument given to PREDICATE is the alist element |
| 1103 | or the symbol from the obarray. | 1104 | or the symbol from the obarray. If ALIST is a hash-table, |
| 1105 | predicate is called with two arguments: the key and the value. | ||
| 1104 | Additionally to this predicate, `completion-regexp-list' | 1106 | Additionally to this predicate, `completion-regexp-list' |
| 1105 | is used to further constrain the set of candidates. */) | 1107 | is used to further constrain the set of candidates. */) |
| 1106 | (string, alist, predicate) | 1108 | (string, alist, predicate) |
| @@ -1111,37 +1113,38 @@ is used to further constrain the set of candidates. */) | |||
| 1111 | int bestmatchsize = 0; | 1113 | int bestmatchsize = 0; |
| 1112 | /* These are in bytes, too. */ | 1114 | /* These are in bytes, too. */ |
| 1113 | int compare, matchsize; | 1115 | int compare, matchsize; |
| 1114 | int list = NILP (alist) || (CONSP (alist) | 1116 | int type = HASH_TABLE_P (alist) ? 3 |
| 1115 | && (!SYMBOLP (XCAR (alist)) | 1117 | : VECTORP (alist) ? 2 |
| 1116 | || NILP (XCAR (alist)))); | 1118 | : NILP (alist) || (CONSP (alist) |
| 1119 | && (!SYMBOLP (XCAR (alist)) | ||
| 1120 | || NILP (XCAR (alist)))); | ||
| 1117 | int index = 0, obsize = 0; | 1121 | int index = 0, obsize = 0; |
| 1118 | int matchcount = 0; | 1122 | int matchcount = 0; |
| 1119 | Lisp_Object bucket, zero, end, tem; | 1123 | Lisp_Object bucket, zero, end, tem; |
| 1120 | struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; | 1124 | struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; |
| 1121 | 1125 | ||
| 1122 | CHECK_STRING (string); | 1126 | CHECK_STRING (string); |
| 1123 | if (!list && !VECTORP (alist)) | 1127 | if (type == 0) |
| 1124 | return call3 (alist, string, predicate, Qnil); | 1128 | return call3 (alist, string, predicate, Qnil); |
| 1125 | 1129 | ||
| 1126 | bestmatch = bucket = Qnil; | 1130 | bestmatch = bucket = Qnil; |
| 1127 | 1131 | ||
| 1128 | /* If ALIST is not a list, set TAIL just for gc pro. */ | 1132 | /* If ALIST is not a list, set TAIL just for gc pro. */ |
| 1129 | tail = alist; | 1133 | tail = alist; |
| 1130 | if (! list) | 1134 | if (type == 2) |
| 1131 | { | 1135 | { |
| 1132 | index = 0; | ||
| 1133 | obsize = XVECTOR (alist)->size; | 1136 | obsize = XVECTOR (alist)->size; |
| 1134 | bucket = XVECTOR (alist)->contents[index]; | 1137 | bucket = XVECTOR (alist)->contents[index]; |
| 1135 | } | 1138 | } |
| 1136 | 1139 | ||
| 1137 | while (1) | 1140 | while (1) |
| 1138 | { | 1141 | { |
| 1139 | /* Get the next element of the alist or obarray. */ | 1142 | /* Get the next element of the alist, obarray, or hash-table. */ |
| 1140 | /* Exit the loop if the elements are all used up. */ | 1143 | /* Exit the loop if the elements are all used up. */ |
| 1141 | /* elt gets the alist element or symbol. | 1144 | /* elt gets the alist element or symbol. |
| 1142 | eltstring gets the name to check as a completion. */ | 1145 | eltstring gets the name to check as a completion. */ |
| 1143 | 1146 | ||
| 1144 | if (list) | 1147 | if (type == 1) |
| 1145 | { | 1148 | { |
| 1146 | if (!CONSP (tail)) | 1149 | if (!CONSP (tail)) |
| 1147 | break; | 1150 | break; |
| @@ -1149,7 +1152,7 @@ is used to further constrain the set of candidates. */) | |||
| 1149 | eltstring = CONSP (elt) ? XCAR (elt) : elt; | 1152 | eltstring = CONSP (elt) ? XCAR (elt) : elt; |
| 1150 | tail = XCDR (tail); | 1153 | tail = XCDR (tail); |
| 1151 | } | 1154 | } |
| 1152 | else | 1155 | else if (type == 2) |
| 1153 | { | 1156 | { |
| 1154 | if (XFASTINT (bucket) != 0) | 1157 | if (XFASTINT (bucket) != 0) |
| 1155 | { | 1158 | { |
| @@ -1168,6 +1171,16 @@ is used to further constrain the set of candidates. */) | |||
| 1168 | continue; | 1171 | continue; |
| 1169 | } | 1172 | } |
| 1170 | } | 1173 | } |
| 1174 | else /* if (type == 3) */ | ||
| 1175 | { | ||
| 1176 | while (index < HASH_TABLE_SIZE (XHASH_TABLE (alist)) | ||
| 1177 | && NILP (HASH_HASH (XHASH_TABLE (alist), index))) | ||
| 1178 | index++; | ||
| 1179 | if (index >= HASH_TABLE_SIZE (XHASH_TABLE (alist))) | ||
| 1180 | break; | ||
| 1181 | else | ||
| 1182 | elt = eltstring = HASH_KEY (XHASH_TABLE (alist), index++); | ||
| 1183 | } | ||
| 1171 | 1184 | ||
| 1172 | /* Is this element a possible completion? */ | 1185 | /* Is this element a possible completion? */ |
| 1173 | 1186 | ||
| @@ -1205,7 +1218,10 @@ is used to further constrain the set of candidates. */) | |||
| 1205 | else | 1218 | else |
| 1206 | { | 1219 | { |
| 1207 | GCPRO4 (tail, string, eltstring, bestmatch); | 1220 | GCPRO4 (tail, string, eltstring, bestmatch); |
| 1208 | tem = call1 (predicate, elt); | 1221 | tem = type == 3 |
| 1222 | ? call2 (predicate, elt, | ||
| 1223 | HASH_VALUE (XHASH_TABLE (alist), index - 1)) | ||
| 1224 | : call1 (predicate, elt); | ||
| 1209 | UNGCPRO; | 1225 | UNGCPRO; |
| 1210 | } | 1226 | } |
| 1211 | if (NILP (tem)) continue; | 1227 | if (NILP (tem)) continue; |
| @@ -1213,9 +1229,9 @@ is used to further constrain the set of candidates. */) | |||
| 1213 | 1229 | ||
| 1214 | /* Update computation of how much all possible completions match */ | 1230 | /* Update computation of how much all possible completions match */ |
| 1215 | 1231 | ||
| 1216 | matchcount++; | ||
| 1217 | if (NILP (bestmatch)) | 1232 | if (NILP (bestmatch)) |
| 1218 | { | 1233 | { |
| 1234 | matchcount = 1; | ||
| 1219 | bestmatch = eltstring; | 1235 | bestmatch = eltstring; |
| 1220 | bestmatchsize = XSTRING (eltstring)->size; | 1236 | bestmatchsize = XSTRING (eltstring)->size; |
| 1221 | } | 1237 | } |
| @@ -1269,6 +1285,10 @@ is used to further constrain the set of candidates. */) | |||
| 1269 | ! EQ (Qt, tem)))) | 1285 | ! EQ (Qt, tem)))) |
| 1270 | bestmatch = eltstring; | 1286 | bestmatch = eltstring; |
| 1271 | } | 1287 | } |
| 1288 | if (bestmatchsize != XSTRING (eltstring)->size | ||
| 1289 | || bestmatchsize != matchsize) | ||
| 1290 | /* Don't count the same string multiple times. */ | ||
| 1291 | matchcount++; | ||
| 1272 | bestmatchsize = matchsize; | 1292 | bestmatchsize = matchsize; |
| 1273 | if (matchsize <= XSTRING (string)->size | 1293 | if (matchsize <= XSTRING (string)->size |
| 1274 | && matchcount > 1) | 1294 | && matchcount > 1) |
| @@ -1308,8 +1328,9 @@ DEFUN ("all-completions", Fall_completions, Sall_completions, 2, 4, 0, | |||
| 1308 | Each car of each element of ALIST is tested to see if it begins with STRING. | 1328 | Each car of each element of ALIST is tested to see if it begins with STRING. |
| 1309 | The value is a list of all the strings from ALIST that match. | 1329 | The value is a list of all the strings from ALIST that match. |
| 1310 | 1330 | ||
| 1311 | ALIST can be an obarray instead of an alist. | 1331 | If ALIST is a hash-table, all the string keys are the possible matches. |
| 1312 | Then the print names of all symbols in the obarray are the possible matches. | 1332 | If ALIST is an obarray, the names of all symbols in the obarray |
| 1333 | are the possible matches. | ||
| 1313 | 1334 | ||
| 1314 | ALIST can also be a function to do the completion itself. | 1335 | ALIST can also be a function to do the completion itself. |
| 1315 | It receives three arguments: the values STRING, PREDICATE and t. | 1336 | It receives three arguments: the values STRING, PREDICATE and t. |
| @@ -1319,7 +1340,8 @@ If optional third argument PREDICATE is non-nil, | |||
| 1319 | it is used to test each possible match. | 1340 | it is used to test each possible match. |
| 1320 | The match is a candidate only if PREDICATE returns non-nil. | 1341 | The match is a candidate only if PREDICATE returns non-nil. |
| 1321 | The argument given to PREDICATE is the alist element | 1342 | The argument given to PREDICATE is the alist element |
| 1322 | or the symbol from the obarray. | 1343 | or the symbol from the obarray. If ALIST is a hash-table, |
| 1344 | predicate is called with two arguments: the key and the value. | ||
| 1323 | Additionally to this predicate, `completion-regexp-list' | 1345 | Additionally to this predicate, `completion-regexp-list' |
| 1324 | is used to further constrain the set of candidates. | 1346 | is used to further constrain the set of candidates. |
| 1325 | 1347 | ||
| @@ -1331,37 +1353,36 @@ are ignored unless STRING itself starts with a space. */) | |||
| 1331 | { | 1353 | { |
| 1332 | Lisp_Object tail, elt, eltstring; | 1354 | Lisp_Object tail, elt, eltstring; |
| 1333 | Lisp_Object allmatches; | 1355 | Lisp_Object allmatches; |
| 1334 | int list = NILP (alist) || (CONSP (alist) | 1356 | int type = HASH_TABLE_P (alist) ? 3 |
| 1335 | && (!SYMBOLP (XCAR (alist)) | 1357 | : VECTORP (alist) ? 2 |
| 1336 | || NILP (XCAR (alist)))); | 1358 | : NILP (alist) || (CONSP (alist) |
| 1359 | && (!SYMBOLP (XCAR (alist)) | ||
| 1360 | || NILP (XCAR (alist)))); | ||
| 1337 | int index = 0, obsize = 0; | 1361 | int index = 0, obsize = 0; |
| 1338 | Lisp_Object bucket, tem; | 1362 | Lisp_Object bucket, tem; |
| 1339 | struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; | 1363 | struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; |
| 1340 | 1364 | ||
| 1341 | CHECK_STRING (string); | 1365 | CHECK_STRING (string); |
| 1342 | if (!list && !VECTORP (alist)) | 1366 | if (type == 0) |
| 1343 | { | 1367 | return call3 (alist, string, predicate, Qt); |
| 1344 | return call3 (alist, string, predicate, Qt); | ||
| 1345 | } | ||
| 1346 | allmatches = bucket = Qnil; | 1368 | allmatches = bucket = Qnil; |
| 1347 | 1369 | ||
| 1348 | /* If ALIST is not a list, set TAIL just for gc pro. */ | 1370 | /* If ALIST is not a list, set TAIL just for gc pro. */ |
| 1349 | tail = alist; | 1371 | tail = alist; |
| 1350 | if (! list) | 1372 | if (type == 2) |
| 1351 | { | 1373 | { |
| 1352 | index = 0; | ||
| 1353 | obsize = XVECTOR (alist)->size; | 1374 | obsize = XVECTOR (alist)->size; |
| 1354 | bucket = XVECTOR (alist)->contents[index]; | 1375 | bucket = XVECTOR (alist)->contents[index]; |
| 1355 | } | 1376 | } |
| 1356 | 1377 | ||
| 1357 | while (1) | 1378 | while (1) |
| 1358 | { | 1379 | { |
| 1359 | /* Get the next element of the alist or obarray. */ | 1380 | /* Get the next element of the alist, obarray, or hash-table. */ |
| 1360 | /* Exit the loop if the elements are all used up. */ | 1381 | /* Exit the loop if the elements are all used up. */ |
| 1361 | /* elt gets the alist element or symbol. | 1382 | /* elt gets the alist element or symbol. |
| 1362 | eltstring gets the name to check as a completion. */ | 1383 | eltstring gets the name to check as a completion. */ |
| 1363 | 1384 | ||
| 1364 | if (list) | 1385 | if (type == 1) |
| 1365 | { | 1386 | { |
| 1366 | if (!CONSP (tail)) | 1387 | if (!CONSP (tail)) |
| 1367 | break; | 1388 | break; |
| @@ -1369,7 +1390,7 @@ are ignored unless STRING itself starts with a space. */) | |||
| 1369 | eltstring = CONSP (elt) ? XCAR (elt) : elt; | 1390 | eltstring = CONSP (elt) ? XCAR (elt) : elt; |
| 1370 | tail = XCDR (tail); | 1391 | tail = XCDR (tail); |
| 1371 | } | 1392 | } |
| 1372 | else | 1393 | else if (type == 2) |
| 1373 | { | 1394 | { |
| 1374 | if (XFASTINT (bucket) != 0) | 1395 | if (XFASTINT (bucket) != 0) |
| 1375 | { | 1396 | { |
| @@ -1388,6 +1409,16 @@ are ignored unless STRING itself starts with a space. */) | |||
| 1388 | continue; | 1409 | continue; |
| 1389 | } | 1410 | } |
| 1390 | } | 1411 | } |
| 1412 | else /* if (type == 3) */ | ||
| 1413 | { | ||
| 1414 | while (index < HASH_TABLE_SIZE (XHASH_TABLE (alist)) | ||
| 1415 | && NILP (HASH_HASH (XHASH_TABLE (alist), index))) | ||
| 1416 | index++; | ||
| 1417 | if (index >= HASH_TABLE_SIZE (XHASH_TABLE (alist))) | ||
| 1418 | break; | ||
| 1419 | else | ||
| 1420 | elt = eltstring = HASH_KEY (XHASH_TABLE (alist), index++); | ||
| 1421 | } | ||
| 1391 | 1422 | ||
| 1392 | /* Is this element a possible completion? */ | 1423 | /* Is this element a possible completion? */ |
| 1393 | 1424 | ||
| @@ -1432,7 +1463,10 @@ are ignored unless STRING itself starts with a space. */) | |||
| 1432 | else | 1463 | else |
| 1433 | { | 1464 | { |
| 1434 | GCPRO4 (tail, eltstring, allmatches, string); | 1465 | GCPRO4 (tail, eltstring, allmatches, string); |
| 1435 | tem = call1 (predicate, elt); | 1466 | tem = type == 3 |
| 1467 | ? call2 (predicate, elt, | ||
| 1468 | HASH_VALUE (XHASH_TABLE (alist), index - 1)) | ||
| 1469 | : call1 (predicate, elt); | ||
| 1436 | UNGCPRO; | 1470 | UNGCPRO; |
| 1437 | } | 1471 | } |
| 1438 | if (NILP (tem)) continue; | 1472 | if (NILP (tem)) continue; |
| @@ -1564,6 +1598,7 @@ the values STRING, PREDICATE and `lambda'. */) | |||
| 1564 | Lisp_Object string, alist, predicate; | 1598 | Lisp_Object string, alist, predicate; |
| 1565 | { | 1599 | { |
| 1566 | Lisp_Object regexps, tem = Qnil; | 1600 | Lisp_Object regexps, tem = Qnil; |
| 1601 | int i = 0; | ||
| 1567 | 1602 | ||
| 1568 | CHECK_STRING (string); | 1603 | CHECK_STRING (string); |
| 1569 | 1604 | ||
| @@ -1571,9 +1606,7 @@ the values STRING, PREDICATE and `lambda'. */) | |||
| 1571 | || NILP (alist)) | 1606 | || NILP (alist)) |
| 1572 | { | 1607 | { |
| 1573 | tem = Fassoc_string (string, alist, completion_ignore_case ? Qt : Qnil); | 1608 | tem = Fassoc_string (string, alist, completion_ignore_case ? Qt : Qnil); |
| 1574 | if (CONSP (tem)) | 1609 | if NILP (tem) |
| 1575 | tem = XCAR (tem); | ||
| 1576 | else | ||
| 1577 | return Qnil; | 1610 | return Qnil; |
| 1578 | } | 1611 | } |
| 1579 | else if (VECTORP (alist)) | 1612 | else if (VECTORP (alist)) |
| @@ -1598,6 +1631,14 @@ the values STRING, PREDICATE and `lambda'. */) | |||
| 1598 | return Qnil; | 1631 | return Qnil; |
| 1599 | } | 1632 | } |
| 1600 | } | 1633 | } |
| 1634 | else if (HASH_TABLE_P (alist)) | ||
| 1635 | { | ||
| 1636 | i = hash_lookup (XHASH_TABLE (alist), string, NULL); | ||
| 1637 | if (i >= 0) | ||
| 1638 | tem = HASH_KEY (XHASH_TABLE (alist), i); | ||
| 1639 | else | ||
| 1640 | return Qnil; | ||
| 1641 | } | ||
| 1601 | else | 1642 | else |
| 1602 | return call3 (alist, string, predicate, Qlambda); | 1643 | return call3 (alist, string, predicate, Qlambda); |
| 1603 | 1644 | ||
| @@ -1613,7 +1654,9 @@ the values STRING, PREDICATE and `lambda'. */) | |||
| 1613 | 1654 | ||
| 1614 | /* Finally, check the predicate. */ | 1655 | /* Finally, check the predicate. */ |
| 1615 | if (!NILP (predicate)) | 1656 | if (!NILP (predicate)) |
| 1616 | return call1 (predicate, tem); | 1657 | return HASH_TABLE_P (alist) |
| 1658 | ? call2 (predicate, tem, HASH_VALUE (XHASH_TABLE (alist), i)) | ||
| 1659 | : call1 (predicate, tem); | ||
| 1617 | else | 1660 | else |
| 1618 | return Qt; | 1661 | return Qt; |
| 1619 | } | 1662 | } |