Function: completion--flex-score-1

completion--flex-score-1 is a byte-compiled function defined in minibuffer.el.gz.

Signature

(completion--flex-score-1 MD-GROUPS MATCH-END LEN)

Documentation

Compute matching score of completion.

The score lies in the range between 0 and 1, where 1 corresponds to the full match.
MD-GROUPS is the "group" part of the match data.
MATCH-END is the end of the match. LEN is the length of the completion string.

Source Code

;; Defined in /usr/src/emacs/lisp/minibuffer.el.gz
(defun completion--flex-score-1 (md-groups match-end len)
  "Compute matching score of completion.
The score lies in the range between 0 and 1, where 1 corresponds to
the full match.
MD-GROUPS is the \"group\"  part of the match data.
MATCH-END is the end of the match.
LEN is the length of the completion string."
  (let* ((from 0)
         ;; To understand how this works, consider these simple
         ;; ascii diagrams showing how the pattern "foo"
         ;; flex-matches "fabrobazo", "fbarbazoo" and
         ;; "barfoobaz":

         ;;      f abr o baz o
         ;;      + --- + --- +

         ;;      f barbaz oo
         ;;      + ------ ++

         ;;      bar foo baz
         ;;          +++

         ;; "+" indicates parts where the pattern matched.  A
         ;; "hole" in the middle of the string is indicated by
         ;; "-".  Note that there are no "holes" near the edges
         ;; of the string.  The completion score is a number
         ;; bound by (0..1] (i.e., larger than (but not equal
         ;; to) zero, and smaller or equal to one): the higher
         ;; the better and only a perfect match (pattern equals
         ;; string) will have score 1.  The formula takes the
         ;; form of a quotient.  For the numerator, we use the
         ;; number of +, i.e. the length of the pattern.  For
         ;; the denominator, it first computes
         ;;
         ;;     hole_i_contrib = 1 + (Li-1)^(1/tightness)
         ;;
         ;; , for each hole "i" of length "Li", where tightness
         ;; is given by `flex-score-match-tightness'.  The
         ;; final value for the denominator is then given by:
         ;;
         ;;    (SUM_across_i(hole_i_contrib) + 1) * len
         ;;
         ;; , where "len" is the string's length.
         (score-numerator 0)
         (score-denominator 0)
         (last-b 0))
    (while (and md-groups (car md-groups))
      (let ((a from)
            (b (pop md-groups)))
        (setq
         score-numerator   (+ score-numerator (- b a)))
        (unless (or (= a last-b)
                    (zerop last-b)
                    (= a len))
          (setq
           score-denominator (+ score-denominator
                                1
                                (expt (- a last-b 1)
                                      (/ 1.0
                                         flex-score-match-tightness)))))
        (setq
         last-b              b))
      (setq from (pop md-groups)))
    ;; If `pattern' doesn't have an explicit trailing any, the
    ;; regex `re' won't produce match data representing the
    ;; region after the match.  We need to account to account
    ;; for that extra bit of match (bug#42149).
    (unless (= from match-end)
      (let ((a from)
            (b match-end))
        (setq
         score-numerator   (+ score-numerator (- b a)))
        (unless (or (= a last-b)
                    (zerop last-b)
                    (= a len))
          (setq
           score-denominator (+ score-denominator
                                1
                                (expt (- a last-b 1)
                                      (/ 1.0
                                         flex-score-match-tightness)))))
        (setq
         last-b              b)))
    (/ score-numerator (* len (1+ score-denominator)) 1.0)))