Function: try-completion

try-completion is a function defined in minibuf.c.

Signature

(try-completion STRING COLLECTION &optional PREDICATE)

Documentation

Return common substring of all completions of STRING in COLLECTION.

Test each possible completion specified by COLLECTION to see if it begins with STRING. The possible completions may be strings or symbols. Symbols are converted to strings before testing, see symbol-name. All that match STRING are compared together; the longest initial sequence common to all these matches is the return value. If there is no match at all, the return value is nil. For a unique match which is exact, the return value is t.

If COLLECTION is an alist, the keys (cars of elements) are the possible completions. If an element is not a cons cell, then the element itself is the possible completion. If COLLECTION is a hash-table, all the keys that are strings or symbols are the possible completions. If COLLECTION is an obarray, the names of all symbols in the obarray are the possible completions.

COLLECTION can also be a function to do the completion itself. It receives three arguments: the values STRING, PREDICATE and nil. Whatever it returns becomes the value of try-completion.

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. If COLLECTION 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.

Other relevant functions are documented in the string group.

Probably introduced at or before Emacs version 19.23.

Shortdoc

;; string
(try-completion "foo" '("foobar" "foozot" "gazonk"))
    => "foo"

Source Code

// Defined in /usr/src/emacs/src/minibuf.c
// Skipping highlighting due to helpful-max-highlight.
{
  Lisp_Object bestmatch, tail, elt, eltstring;
  /* Size in bytes of BESTMATCH.  */
  ptrdiff_t bestmatchsize = 0;
  /* These are in bytes, too.  */
  ptrdiff_t compare, matchsize;
  enum { function_table, list_table, obarray_table, hash_table}
    type = (HASH_TABLE_P (collection) ? hash_table
	    : VECTORP (collection) ? obarray_table
	    : ((NILP (collection)
		|| (CONSP (collection) && !FUNCTIONP (collection)))
	       ? list_table : function_table));
  ptrdiff_t idx = 0, obsize = 0;
  int matchcount = 0;
  ptrdiff_t bindcount = -1;
  Lisp_Object bucket, zero, end, tem;

  CHECK_STRING (string);
  if (type == function_table)
    return call3 (collection, string, predicate, Qnil);

  bestmatch = bucket = Qnil;
  zero = make_fixnum (0);

  /* If COLLECTION is not a list, set TAIL just for gc pro.  */
  tail = collection;
  if (type == obarray_table)
    {
      collection = check_obarray (collection);
      obsize = ASIZE (collection);
      bucket = AREF (collection, idx);
    }

  while (1)
    {
      /* 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 (type == list_table)
	{
	  if (!CONSP (tail))
	    break;
	  elt = XCAR (tail);
	  eltstring = CONSP (elt) ? XCAR (elt) : elt;
	  tail = XCDR (tail);
	}
      else if (type == obarray_table)
	{
	  if (!EQ (bucket, zero))
	    {
	      if (!SYMBOLP (bucket))
		error ("Bad data in guts of obarray");
	      elt = bucket;
	      eltstring = elt;
	      if (XSYMBOL (bucket)->u.s.next)
		XSETSYMBOL (bucket, XSYMBOL (bucket)->u.s.next);
	      else
		XSETFASTINT (bucket, 0);
	    }
	  else if (++idx >= obsize)
	    break;
	  else
	    {
	      bucket = AREF (collection, idx);
	      continue;
	    }
	}
      else /* if (type == hash_table) */
	{
	  while (idx < HASH_TABLE_SIZE (XHASH_TABLE (collection))
		 && EQ (HASH_KEY (XHASH_TABLE (collection), idx), Qunbound))
	    idx++;
	  if (idx >= HASH_TABLE_SIZE (XHASH_TABLE (collection)))
	    break;
	  else
	    elt = eltstring = HASH_KEY (XHASH_TABLE (collection), idx++);
	}

      /* Is this element a possible completion?  */

      if (SYMBOLP (eltstring))
	eltstring = Fsymbol_name (eltstring);

      if (STRINGP (eltstring)
	  && SCHARS (string) <= SCHARS (eltstring)
	  && (tem = Fcompare_strings (eltstring, zero,
				      make_fixnum (SCHARS (string)),
				      string, zero, Qnil,
				      completion_ignore_case ? Qt : Qnil),
	      EQ (Qt, tem)))
	{
	  /* Yes.  */
	  Lisp_Object regexps;

	  /* Ignore this element if it fails to match all the regexps.  */
	  {
	    for (regexps = Vcompletion_regexp_list; CONSP (regexps);
		 regexps = XCDR (regexps))
	      {
		if (bindcount < 0)
		  {
		    bindcount = SPECPDL_INDEX ();
		    specbind (Qcase_fold_search,
			      completion_ignore_case ? Qt : Qnil);
		  }
		tem = Fstring_match (XCAR (regexps), eltstring, zero);
		if (NILP (tem))
		  break;
	      }
	    if (CONSP (regexps))
	      continue;
	  }

	  /* Ignore this element if there is a predicate
	     and the predicate doesn't like it.  */

	  if (!NILP (predicate))
	    {
	      if (EQ (predicate, Qcommandp))
		tem = Fcommandp (elt, Qnil);
	      else
		{
		  if (bindcount >= 0)
		    {
		      unbind_to (bindcount, Qnil);
		      bindcount = -1;
		    }
		  tem = (type == hash_table
			 ? call2 (predicate, elt,
				  HASH_VALUE (XHASH_TABLE (collection),
					      idx - 1))
			 : call1 (predicate, elt));
		}
	      if (NILP (tem)) continue;
	    }

	  /* Update computation of how much all possible completions match */

	  if (NILP (bestmatch))
	    {
	      matchcount = 1;
	      bestmatch = eltstring;
	      bestmatchsize = SCHARS (eltstring);
	    }
	  else
	    {
	      compare = min (bestmatchsize, SCHARS (eltstring));
	      Lisp_Object lcompare = make_fixnum (compare);
	      tem = Fcompare_strings (bestmatch, zero, lcompare,
				      eltstring, zero, lcompare,
				      completion_ignore_case ? Qt : Qnil);
	      matchsize = EQ (tem, Qt) ? compare : eabs (XFIXNUM (tem)) - 1;

	      Lisp_Object old_bestmatch = bestmatch;
	      if (completion_ignore_case)
		{
		  /* If this is an exact match except for case,
		     use it as the best match rather than one that is not an
		     exact match.  This way, we get the case pattern
		     of the actual match.  */
		  if ((matchsize == SCHARS (eltstring)
		       && matchsize < SCHARS (bestmatch))
		      ||
		      /* If there is more than one exact match ignoring case,
			 and one of them is exact including case,
			 prefer that one.  */
		      /* If there is no exact match ignoring case,
			 prefer a match that does not change the case
			 of the input.  */
		      ((matchsize == SCHARS (eltstring))
		       ==
		       (matchsize == SCHARS (bestmatch))
		       && (tem = Fcompare_strings (eltstring, zero,
						   make_fixnum (SCHARS (string)),
						   string, zero,
						   Qnil,
						   Qnil),
			   EQ (Qt, tem))
		       && (tem = Fcompare_strings (bestmatch, zero,
						   make_fixnum (SCHARS (string)),
						   string, zero,
						   Qnil,
						   Qnil),
			   ! EQ (Qt, tem))))
		    bestmatch = eltstring;
		}
	      if (bestmatchsize != SCHARS (eltstring)
		  || bestmatchsize != matchsize
		  || (completion_ignore_case
		      && !EQ (Fcompare_strings (old_bestmatch, zero, lcompare,
						eltstring, zero, lcompare,
						Qnil),
			      Qt)))
		/* Don't count the same string multiple times.  */
		matchcount += matchcount <= 1;
	      bestmatchsize = matchsize;
	      if (matchsize <= SCHARS (string)
		  /* If completion-ignore-case is non-nil, don't
		     short-circuit because we want to find the best
		     possible match *including* case differences.  */
		  && !completion_ignore_case
		  && matchcount > 1)
		/* No need to look any further.  */
		break;
	    }
	}
    }

  if (bindcount >= 0)
    unbind_to (bindcount, Qnil);

  if (NILP (bestmatch))
    return Qnil;		/* No completions found.  */
  /* If we are ignoring case, and there is no exact match,
     and no additional text was supplied,
     don't change the case of what the user typed.  */
  if (completion_ignore_case && bestmatchsize == SCHARS (string)
      && SCHARS (bestmatch) > bestmatchsize)
    return minibuf_conform_representation (string, bestmatch);

  /* Return t if the supplied string is an exact match (counting case);
     it does not require any change to be made.  */
  if (matchcount == 1 && !NILP (Fequal (bestmatch, string)))
    return Qt;

  XSETFASTINT (zero, 0);		/* Else extract the part in which */
  XSETFASTINT (end, bestmatchsize);	/* all completions agree.  */
  return Fsubstring (bestmatch, zero, end);
}