# HG changeset patch # User Stefan Monnier # Date 1018380522 0 # Node ID f9a82a50692ed9a2bbaa6bcfd2532c11105fd000 # Parent 539150b681264dcc41d9f67bbcf3c4411cfd2393 (read_minibuf): Use empty_string. (Ftry_completion): Allow lambda forms and lists of strings for `alist'. Short-circuit the search as soon as it "failed". (Fall_completions): Allow lambda forms and lists of strings for alist. (Fcompleting_read): Set Qminibuffer_completion_confirm to nil when require_match is nil. (Ftest_completion): Rename from `test_completion' and export to elisp. Call the predicate also when alist is a list. Obey Vcompletion_regexp_list. (do_completion, Fminibuffer_complete_and_exit): Use it. (Fassoc_string): Rename from `assoc_for_completion'. Allow list of strings as well and export to elisp. diff -r 539150b68126 -r f9a82a50692e src/minibuf.c --- a/src/minibuf.c Tue Apr 09 18:56:34 2002 +0000 +++ b/src/minibuf.c Tue Apr 09 19:28:42 2002 +0000 @@ -427,7 +427,7 @@ GCPRO5 (map, initial, val, ambient_dir, input_method); if (!STRINGP (prompt)) - prompt = build_string (""); + prompt = empty_string; if (!enable_recursive_minibuffers && minibuf_level > 0) @@ -1103,7 +1103,9 @@ int bestmatchsize = 0; /* These are in bytes, too. */ int compare, matchsize; - int list = CONSP (alist) || NILP (alist); + int list = NILP (alist) || (CONSP (alist) + && (!SYMBOLP (XCAR (alist)) + || NILP (XCAR (alist)))); int index = 0, obsize = 0; int matchcount = 0; Lisp_Object bucket, zero, end, tem; @@ -1133,11 +1135,11 @@ if (list) { - if (NILP (tail)) + if (!CONSP (tail)) break; - elt = Fcar (tail); - eltstring = Fcar (elt); - tail = Fcdr (tail); + elt = XCAR (tail); + eltstring = CONSP (elt) ? XCAR (elt) : elt; + tail = XCDR (tail); } else { @@ -1225,6 +1227,7 @@ matchsize = XINT (tem) - 1; if (matchsize < 0) + /* When can this happen ? -stef */ matchsize = compare; if (completion_ignore_case) { @@ -1259,6 +1262,10 @@ bestmatch = eltstring; } bestmatchsize = matchsize; + if (matchsize <= XSTRING (string)->size + && matchcount > 1) + /* No need to look any further. */ + break; } } } @@ -1316,7 +1323,9 @@ { Lisp_Object tail, elt, eltstring; Lisp_Object allmatches; - int list = CONSP (alist) || NILP (alist); + int list = 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; @@ -1346,11 +1355,11 @@ if (list) { - if (NILP (tail)) + if (!CONSP (tail)) break; - elt = Fcar (tail); - eltstring = Fcar (elt); - tail = Fcdr (tail); + elt = XCAR (tail); + eltstring = CONSP (elt) ? XCAR (elt) : elt; + tail = XCDR (tail); } else { @@ -1486,7 +1495,7 @@ specbind (Qminibuffer_completion_table, table); specbind (Qminibuffer_completion_predicate, predicate); specbind (Qminibuffer_completion_confirm, - EQ (require_match, Qt) ? Qnil : Qt); + EQ (require_match, Qt) ? Qnil : require_match); last_exact_completion = Qnil; position = Qnil; @@ -1535,47 +1544,70 @@ } Lisp_Object Fminibuffer_completion_help (); -Lisp_Object assoc_for_completion (); +Lisp_Object Fassoc_string (); /* Test whether TXT is an exact completion. */ -Lisp_Object -test_completion (txt) - Lisp_Object txt; +DEFUN ("test-completion", Ftest_completion, Stest_completion, 2, 3, 0, + doc: /* Return non-nil if STRING is a valid completion. +Takes the same arguments as `all-completions' and `try-completion'. +If ALIST is a function, it is called with three arguments: +the values STRING, PREDICATE and `lambda'. */) + (string, alist, predicate) + Lisp_Object string, alist, predicate; { - Lisp_Object tem; + Lisp_Object regexps, tem = Qnil; + + CHECK_STRING (string); - if (CONSP (Vminibuffer_completion_table) - || NILP (Vminibuffer_completion_table)) - return assoc_for_completion (txt, Vminibuffer_completion_table); - else if (VECTORP (Vminibuffer_completion_table)) + if ((CONSP (alist) && (!SYMBOLP (XCAR (alist)) || NILP (XCAR (alist)))) + || NILP (alist)) { - /* Bypass intern-soft as that loses for nil */ - tem = oblookup (Vminibuffer_completion_table, - XSTRING (txt)->data, - XSTRING (txt)->size, - STRING_BYTES (XSTRING (txt))); + tem = Fassoc_string (string, alist, completion_ignore_case ? Qt : Qnil); + if (CONSP (tem)) + tem = XCAR (tem); + else + return Qnil; + } + else if (VECTORP (alist)) + { + /* Bypass intern-soft as that loses for nil. */ + tem = oblookup (alist, + XSTRING (string)->data, + XSTRING (string)->size, + STRING_BYTES (XSTRING (string))); if (!SYMBOLP (tem)) { - if (STRING_MULTIBYTE (txt)) - txt = Fstring_make_unibyte (txt); + if (STRING_MULTIBYTE (string)) + string = Fstring_make_unibyte (string); else - txt = Fstring_make_multibyte (txt); + string = Fstring_make_multibyte (string); tem = oblookup (Vminibuffer_completion_table, - XSTRING (txt)->data, - XSTRING (txt)->size, - STRING_BYTES (XSTRING (txt))); + XSTRING (string)->data, + XSTRING (string)->size, + STRING_BYTES (XSTRING (string))); if (!SYMBOLP (tem)) return Qnil; } - if (!NILP (Vminibuffer_completion_predicate)) - return call1 (Vminibuffer_completion_predicate, tem); - else - return Qt; } else - return call3 (Vminibuffer_completion_table, txt, - Vminibuffer_completion_predicate, Qlambda); + return call3 (alist, string, predicate, Qlambda); + + /* Reject this element if it fails to match all the regexps. */ + for (regexps = Vcompletion_regexp_list; CONSP (regexps); + regexps = XCDR (regexps)) + { + if (NILP (Fstring_match (XCAR (regexps), + SYMBOLP (tem) ? string : tem, + Qnil))) + return Qnil; + } + + /* Finally, check the predicate. */ + if (!NILP (predicate)) + return call1 (predicate, tem); + else + return Qt; } /* returns: @@ -1645,7 +1677,9 @@ } /* It did find a match. Do we match some possibility exactly now? */ - tem = test_completion (Fminibuffer_contents ()); + tem = Ftest_completion (Fminibuffer_contents (), + Vminibuffer_completion_table, + Vminibuffer_completion_predicate); if (NILP (tem)) { /* not an exact match */ @@ -1679,10 +1713,15 @@ /* Like assoc but assumes KEY is a string, and ignores case if appropriate. */ -Lisp_Object -assoc_for_completion (key, list) +DEFUN ("assoc-string", Fassoc_string, Sassoc_string, 2, 3, 0, + doc: /* Like `assoc' but specifically for strings. +Unibyte strings are converted to multibyte for comparison. +And case is ignored if CASE-FOLD is non-nil. +As opposed to `assoc', it will also match an entry consisting of a single +string rather than a cons cell whose car is a string. */) + (key, list, case_fold) register Lisp_Object key; - Lisp_Object list; + Lisp_Object list, case_fold; { register Lisp_Object tail; @@ -1690,13 +1729,12 @@ { register Lisp_Object elt, tem, thiscar; elt = Fcar (tail); - if (!CONSP (elt)) continue; - thiscar = Fcar (elt); + thiscar = CONSP (elt) ? XCAR (elt) : elt; if (!STRINGP (thiscar)) continue; tem = Fcompare_strings (thiscar, make_number (0), Qnil, key, make_number (0), Qnil, - completion_ignore_case ? Qt : Qnil); + case_fold); if (EQ (tem, Qt)) return elt; QUIT; @@ -1797,7 +1835,9 @@ if (XINT (Fminibuffer_prompt_end ()) == ZV) goto exit; - if (!NILP (test_completion (Fminibuffer_contents ()))) + if (!NILP (Ftest_completion (Fminibuffer_contents (), + Vminibuffer_completion_table, + Vminibuffer_completion_predicate))) goto exit; /* Call do_completion, but ignore errors. */ @@ -2476,6 +2516,8 @@ defsubr (&Stry_completion); defsubr (&Sall_completions); + defsubr (&Stest_completion); + defsubr (&Sassoc_string); defsubr (&Scompleting_read); defsubr (&Sminibuffer_complete); defsubr (&Sminibuffer_complete_word);