aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMiha Rihtaršič2021-10-19 18:41:13 +0200
committerLars Ingebrigtsen2021-10-20 10:20:03 +0200
commit7a6cc97f3c2fe8c01ac71e39514a73c0674b9061 (patch)
treecd820c07b8a3275c172c5f79f72c37b27455b553 /src
parent1fb8a1569dab5a5cb99afad9678b3bebae1733c5 (diff)
downloademacs-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.c105
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
1548static bool
1549match_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
1548DEFUN ("try-completion", Ftry_completion, Stry_completion, 2, 3, 0, 1569DEFUN ("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.
1550Test each possible completion specified by COLLECTION 1571Test each possible completion specified by COLLECTION
@@ -1578,6 +1599,7 @@ Additionally to this predicate, `completion-regexp-list'
1578is used to further constrain the set of candidates. */) 1599is 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:
2068the values STRING, PREDICATE and `lambda'. */) 2038the 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))