diff options
| author | Miha Rihtaršič | 2021-10-19 18:41:13 +0200 |
|---|---|---|
| committer | Lars Ingebrigtsen | 2021-10-20 10:20:03 +0200 |
| commit | 7a6cc97f3c2fe8c01ac71e39514a73c0674b9061 (patch) | |
| tree | cd820c07b8a3275c172c5f79f72c37b27455b553 /src | |
| parent | 1fb8a1569dab5a5cb99afad9678b3bebae1733c5 (diff) | |
| download | emacs-7a6cc97f3c2fe8c01ac71e39514a73c0674b9061.tar.gz emacs-7a6cc97f3c2fe8c01ac71e39514a73c0674b9061.zip | |
Avoid excessive specbinding in all-completions
* src/minibuf.c (match_regexps):
(Ftry_completion):
(Fall_completions):
(Ftest_completion): Use fast_string_match_internal to match against
regexps in completion-regexp-list without having to bind
case-fold-search.
Diffstat (limited to 'src')
| -rw-r--r-- | src/minibuf.c | 105 |
1 files changed, 32 insertions, 73 deletions
diff --git a/src/minibuf.c b/src/minibuf.c index 0dc340e9670..6c0cd358c50 100644 --- a/src/minibuf.c +++ b/src/minibuf.c | |||
| @@ -1545,6 +1545,27 @@ minibuf_conform_representation (Lisp_Object string, Lisp_Object basis) | |||
| 1545 | return Fstring_make_multibyte (string); | 1545 | return Fstring_make_multibyte (string); |
| 1546 | } | 1546 | } |
| 1547 | 1547 | ||
| 1548 | static bool | ||
| 1549 | match_regexps (Lisp_Object string, Lisp_Object regexps, | ||
| 1550 | bool ignore_case) | ||
| 1551 | { | ||
| 1552 | ptrdiff_t val; | ||
| 1553 | for (; CONSP (regexps); regexps = XCDR (regexps)) | ||
| 1554 | { | ||
| 1555 | CHECK_STRING (XCAR (regexps)); | ||
| 1556 | |||
| 1557 | val = fast_string_match_internal | ||
| 1558 | (XCAR (regexps), string, | ||
| 1559 | (ignore_case ? BVAR (current_buffer, case_canon_table) : Qnil)); | ||
| 1560 | |||
| 1561 | if (val == -2) | ||
| 1562 | error ("Stack overflow in regexp matcher"); | ||
| 1563 | if (val < 0) | ||
| 1564 | return false; | ||
| 1565 | } | ||
| 1566 | return true; | ||
| 1567 | } | ||
| 1568 | |||
| 1548 | DEFUN ("try-completion", Ftry_completion, Stry_completion, 2, 3, 0, | 1569 | DEFUN ("try-completion", Ftry_completion, Stry_completion, 2, 3, 0, |
| 1549 | doc: /* Return common substring of all completions of STRING in COLLECTION. | 1570 | doc: /* Return common substring of all completions of STRING in COLLECTION. |
| 1550 | Test each possible completion specified by COLLECTION | 1571 | Test each possible completion specified by COLLECTION |
| @@ -1578,6 +1599,7 @@ Additionally to this predicate, `completion-regexp-list' | |||
| 1578 | is used to further constrain the set of candidates. */) | 1599 | is used to further constrain the set of candidates. */) |
| 1579 | (Lisp_Object string, Lisp_Object collection, Lisp_Object predicate) | 1600 | (Lisp_Object string, Lisp_Object collection, Lisp_Object predicate) |
| 1580 | { | 1601 | { |
| 1602 | |||
| 1581 | Lisp_Object bestmatch, tail, elt, eltstring; | 1603 | Lisp_Object bestmatch, tail, elt, eltstring; |
| 1582 | /* Size in bytes of BESTMATCH. */ | 1604 | /* Size in bytes of BESTMATCH. */ |
| 1583 | ptrdiff_t bestmatchsize = 0; | 1605 | ptrdiff_t bestmatchsize = 0; |
| @@ -1591,7 +1613,6 @@ is used to further constrain the set of candidates. */) | |||
| 1591 | ? list_table : function_table)); | 1613 | ? list_table : function_table)); |
| 1592 | ptrdiff_t idx = 0, obsize = 0; | 1614 | ptrdiff_t idx = 0, obsize = 0; |
| 1593 | int matchcount = 0; | 1615 | int matchcount = 0; |
| 1594 | ptrdiff_t bindcount = -1; | ||
| 1595 | Lisp_Object bucket, zero, end, tem; | 1616 | Lisp_Object bucket, zero, end, tem; |
| 1596 | 1617 | ||
| 1597 | CHECK_STRING (string); | 1618 | CHECK_STRING (string); |
| @@ -1670,27 +1691,10 @@ is used to further constrain the set of candidates. */) | |||
| 1670 | completion_ignore_case ? Qt : Qnil), | 1691 | completion_ignore_case ? Qt : Qnil), |
| 1671 | EQ (Qt, tem))) | 1692 | EQ (Qt, tem))) |
| 1672 | { | 1693 | { |
| 1673 | /* Yes. */ | ||
| 1674 | Lisp_Object regexps; | ||
| 1675 | |||
| 1676 | /* Ignore this element if it fails to match all the regexps. */ | 1694 | /* Ignore this element if it fails to match all the regexps. */ |
| 1677 | { | 1695 | if (!match_regexps (eltstring, Vcompletion_regexp_list, |
| 1678 | for (regexps = Vcompletion_regexp_list; CONSP (regexps); | 1696 | completion_ignore_case)) |
| 1679 | regexps = XCDR (regexps)) | 1697 | continue; |
| 1680 | { | ||
| 1681 | if (bindcount < 0) | ||
| 1682 | { | ||
| 1683 | bindcount = SPECPDL_INDEX (); | ||
| 1684 | specbind (Qcase_fold_search, | ||
| 1685 | completion_ignore_case ? Qt : Qnil); | ||
| 1686 | } | ||
| 1687 | tem = Fstring_match (XCAR (regexps), eltstring, zero, Qnil); | ||
| 1688 | if (NILP (tem)) | ||
| 1689 | break; | ||
| 1690 | } | ||
| 1691 | if (CONSP (regexps)) | ||
| 1692 | continue; | ||
| 1693 | } | ||
| 1694 | 1698 | ||
| 1695 | /* Ignore this element if there is a predicate | 1699 | /* Ignore this element if there is a predicate |
| 1696 | and the predicate doesn't like it. */ | 1700 | and the predicate doesn't like it. */ |
| @@ -1701,11 +1705,6 @@ is used to further constrain the set of candidates. */) | |||
| 1701 | tem = Fcommandp (elt, Qnil); | 1705 | tem = Fcommandp (elt, Qnil); |
| 1702 | else | 1706 | else |
| 1703 | { | 1707 | { |
| 1704 | if (bindcount >= 0) | ||
| 1705 | { | ||
| 1706 | unbind_to (bindcount, Qnil); | ||
| 1707 | bindcount = -1; | ||
| 1708 | } | ||
| 1709 | tem = (type == hash_table | 1708 | tem = (type == hash_table |
| 1710 | ? call2 (predicate, elt, | 1709 | ? call2 (predicate, elt, |
| 1711 | HASH_VALUE (XHASH_TABLE (collection), | 1710 | HASH_VALUE (XHASH_TABLE (collection), |
| @@ -1787,9 +1786,6 @@ is used to further constrain the set of candidates. */) | |||
| 1787 | } | 1786 | } |
| 1788 | } | 1787 | } |
| 1789 | 1788 | ||
| 1790 | if (bindcount >= 0) | ||
| 1791 | unbind_to (bindcount, Qnil); | ||
| 1792 | |||
| 1793 | if (NILP (bestmatch)) | 1789 | if (NILP (bestmatch)) |
| 1794 | return Qnil; /* No completions found. */ | 1790 | return Qnil; /* No completions found. */ |
| 1795 | /* If we are ignoring case, and there is no exact match, | 1791 | /* If we are ignoring case, and there is no exact match, |
| @@ -1849,7 +1845,6 @@ with a space are ignored unless STRING itself starts with a space. */) | |||
| 1849 | : VECTORP (collection) ? 2 | 1845 | : VECTORP (collection) ? 2 |
| 1850 | : NILP (collection) || (CONSP (collection) && !FUNCTIONP (collection)); | 1846 | : NILP (collection) || (CONSP (collection) && !FUNCTIONP (collection)); |
| 1851 | ptrdiff_t idx = 0, obsize = 0; | 1847 | ptrdiff_t idx = 0, obsize = 0; |
| 1852 | ptrdiff_t bindcount = -1; | ||
| 1853 | Lisp_Object bucket, tem, zero; | 1848 | Lisp_Object bucket, tem, zero; |
| 1854 | 1849 | ||
| 1855 | CHECK_STRING (string); | 1850 | CHECK_STRING (string); |
| @@ -1934,27 +1929,10 @@ with a space are ignored unless STRING itself starts with a space. */) | |||
| 1934 | completion_ignore_case ? Qt : Qnil), | 1929 | completion_ignore_case ? Qt : Qnil), |
| 1935 | EQ (Qt, tem))) | 1930 | EQ (Qt, tem))) |
| 1936 | { | 1931 | { |
| 1937 | /* Yes. */ | ||
| 1938 | Lisp_Object regexps; | ||
| 1939 | |||
| 1940 | /* Ignore this element if it fails to match all the regexps. */ | 1932 | /* Ignore this element if it fails to match all the regexps. */ |
| 1941 | { | 1933 | if (!match_regexps (eltstring, Vcompletion_regexp_list, |
| 1942 | for (regexps = Vcompletion_regexp_list; CONSP (regexps); | 1934 | completion_ignore_case)) |
| 1943 | regexps = XCDR (regexps)) | 1935 | continue; |
| 1944 | { | ||
| 1945 | if (bindcount < 0) | ||
| 1946 | { | ||
| 1947 | bindcount = SPECPDL_INDEX (); | ||
| 1948 | specbind (Qcase_fold_search, | ||
| 1949 | completion_ignore_case ? Qt : Qnil); | ||
| 1950 | } | ||
| 1951 | tem = Fstring_match (XCAR (regexps), eltstring, zero, Qnil); | ||
| 1952 | if (NILP (tem)) | ||
| 1953 | break; | ||
| 1954 | } | ||
| 1955 | if (CONSP (regexps)) | ||
| 1956 | continue; | ||
| 1957 | } | ||
| 1958 | 1936 | ||
| 1959 | /* Ignore this element if there is a predicate | 1937 | /* Ignore this element if there is a predicate |
| 1960 | and the predicate doesn't like it. */ | 1938 | and the predicate doesn't like it. */ |
| @@ -1965,11 +1943,6 @@ with a space are ignored unless STRING itself starts with a space. */) | |||
| 1965 | tem = Fcommandp (elt, Qnil); | 1943 | tem = Fcommandp (elt, Qnil); |
| 1966 | else | 1944 | else |
| 1967 | { | 1945 | { |
| 1968 | if (bindcount >= 0) | ||
| 1969 | { | ||
| 1970 | unbind_to (bindcount, Qnil); | ||
| 1971 | bindcount = -1; | ||
| 1972 | } | ||
| 1973 | tem = type == 3 | 1946 | tem = type == 3 |
| 1974 | ? call2 (predicate, elt, | 1947 | ? call2 (predicate, elt, |
| 1975 | HASH_VALUE (XHASH_TABLE (collection), idx - 1)) | 1948 | HASH_VALUE (XHASH_TABLE (collection), idx - 1)) |
| @@ -1982,9 +1955,6 @@ with a space are ignored unless STRING itself starts with a space. */) | |||
| 1982 | } | 1955 | } |
| 1983 | } | 1956 | } |
| 1984 | 1957 | ||
| 1985 | if (bindcount >= 0) | ||
| 1986 | unbind_to (bindcount, Qnil); | ||
| 1987 | |||
| 1988 | return Fnreverse (allmatches); | 1958 | return Fnreverse (allmatches); |
| 1989 | } | 1959 | } |
| 1990 | 1960 | ||
| @@ -2068,7 +2038,7 @@ If COLLECTION is a function, it is called with three arguments: | |||
| 2068 | the values STRING, PREDICATE and `lambda'. */) | 2038 | the values STRING, PREDICATE and `lambda'. */) |
| 2069 | (Lisp_Object string, Lisp_Object collection, Lisp_Object predicate) | 2039 | (Lisp_Object string, Lisp_Object collection, Lisp_Object predicate) |
| 2070 | { | 2040 | { |
| 2071 | Lisp_Object regexps, tail, tem = Qnil; | 2041 | Lisp_Object tail, tem = Qnil; |
| 2072 | ptrdiff_t i = 0; | 2042 | ptrdiff_t i = 0; |
| 2073 | 2043 | ||
| 2074 | CHECK_STRING (string); | 2044 | CHECK_STRING (string); |
| @@ -2154,20 +2124,9 @@ the values STRING, PREDICATE and `lambda'. */) | |||
| 2154 | return call3 (collection, string, predicate, Qlambda); | 2124 | return call3 (collection, string, predicate, Qlambda); |
| 2155 | 2125 | ||
| 2156 | /* Reject this element if it fails to match all the regexps. */ | 2126 | /* Reject this element if it fails to match all the regexps. */ |
| 2157 | if (CONSP (Vcompletion_regexp_list)) | 2127 | if (!match_regexps (string, Vcompletion_regexp_list, |
| 2158 | { | 2128 | completion_ignore_case)) |
| 2159 | ptrdiff_t count = SPECPDL_INDEX (); | 2129 | return Qnil; |
| 2160 | specbind (Qcase_fold_search, completion_ignore_case ? Qt : Qnil); | ||
| 2161 | for (regexps = Vcompletion_regexp_list; CONSP (regexps); | ||
| 2162 | regexps = XCDR (regexps)) | ||
| 2163 | { | ||
| 2164 | /* We can test against STRING, because if we got here, then | ||
| 2165 | the element is equivalent to it. */ | ||
| 2166 | if (NILP (Fstring_match (XCAR (regexps), string, Qnil, Qnil))) | ||
| 2167 | return unbind_to (count, Qnil); | ||
| 2168 | } | ||
| 2169 | unbind_to (count, Qnil); | ||
| 2170 | } | ||
| 2171 | 2130 | ||
| 2172 | /* Finally, check the predicate. */ | 2131 | /* Finally, check the predicate. */ |
| 2173 | if (!NILP (predicate)) | 2132 | if (!NILP (predicate)) |