branch: externals/orderless
commit 2c952fd161f95dd2b92aff5ffaeb50ab4e39ed10
Merge: b24748093b 9e515ee9a3
Author: Omar AntolĂn Camarena <[email protected]>
Commit: GitHub <[email protected]>
Merge pull request #161 from minad/optimize-predicate
Optimizations and refactoring
---
orderless.el | 147 ++++++++++++++++++++++++++++++-----------------------------
1 file changed, 74 insertions(+), 73 deletions(-)
diff --git a/orderless.el b/orderless.el
index e914a6b8a1..15a359b75b 100644
--- a/orderless.el
+++ b/orderless.el
@@ -7,7 +7,7 @@
;; Keywords: extensions
;; Version: 1.0
;; Homepage: https://github.com/oantolin/orderless
-;; Package-Requires: ((emacs "26.1"))
+;; Package-Requires: ((emacs "27.1"))
;; This file is part of GNU Emacs.
@@ -216,9 +216,9 @@ is determined by the values of `completion-ignore-case',
(progn (string-match-p component "") component)
(invalid-regexp nil)))
-(defalias 'orderless-literal #'regexp-quote
- "Match a component as a literal string.
-This is simply `regexp-quote'.")
+(defun orderless-literal (component)
+ "Match COMPONENT as a literal string."
+ `(literal ,component))
(defun orderless--separated-by (sep rxs &optional before after)
"Return a regexp to match the rx-regexps RXS with SEP in between.
@@ -226,22 +226,20 @@ If BEFORE is specified, add it to the beginning of the rx
sequence. If AFTER is specified, add it to the end of the rx
sequence."
(declare (indent 1))
- (rx-to-string
- `(seq
- ,(or before "")
- ,@(cl-loop for (sexp . more) on rxs
- collect `(group ,sexp)
- when more collect sep)
- ,(or after ""))))
+ `(seq
+ ,(or before "")
+ ,@(cl-loop for (sexp . more) on rxs
+ collect `(group ,sexp)
+ when more collect sep)
+ ,(or after "")))
(defun orderless-flex (component)
"Match a component in flex style.
This means the characters in COMPONENT must occur in the
candidate in that order, but not necessarily consecutively."
- (rx-to-string
- `(seq
- ,@(cdr (cl-loop for char across component
- append `((zero-or-more (not ,char)) (group ,char)))))))
+ `(seq
+ ,@(cdr (cl-loop for char across component
+ append `((zero-or-more (not ,char)) (group ,char))))))
(defun orderless-initialism (component)
"Match a component as an initialism.
@@ -261,15 +259,14 @@ at a word boundary in the candidate. This is similar to
the
(defun orderless-without-literal (component)
"Match strings that do *not* contain COMPONENT as a literal match."
- (rx-to-string
- `(seq
- (group string-start) ; highlight nothing!
- (zero-or-more
- (or ,@(cl-loop for i below (length component)
- collect `(seq ,(substring component 0 i)
- (or (not (any ,(aref component i)))
- string-end)))))
- string-end)))
+ `(seq
+ (group string-start) ; highlight nothing!
+ (zero-or-more
+ (or ,@(cl-loop for i below (length component)
+ collect `(seq ,(substring component 0 i)
+ (or (not (any ,(aref component i)))
+ string-end)))))
+ string-end))
;;; Highlighting matches
@@ -384,16 +381,20 @@ as the value of DISPATCHERS."
when (functionp newstyles) do (setq newstyles (list newstyles))
for regexps = (cl-loop for style in newstyles
for result = (funcall style newcomp)
- when result collect `(regexp ,result))
+ when result collect
+ (if (stringp result) `(regexp ,result) result))
when regexps collect (rx-to-string `(or ,@(delete-dups regexps)))))
;;; Completion style implementation
-(defun orderless--prefix+pattern (string table pred)
- "Split STRING into prefix and pattern according to TABLE.
+(defun orderless--compile (string table pred)
+ "Compile STRING to a prefix and a list of regular expressions.
The predicate PRED is used to constrain the entries in TABLE."
- (let ((limit (car (completion-boundaries string table pred ""))))
- (cons (substring string 0 limit) (substring string limit))))
+ (let* ((limit (car (completion-boundaries string table pred "")))
+ (prefix (substring string 0 limit))
+ (pattern (substring string limit))
+ (regexps (orderless-pattern-compiler pattern)))
+ (list prefix regexps (orderless--ignore-case-p regexps))))
;; Thanks to @jakanakaevangeli for writing a version of this function:
;; https://github.com/oantolin/orderless/issues/79#issuecomment-916073526
@@ -418,25 +419,26 @@ then return (cons REGEXP u); else return nil."
always (isearch-no-upper-case-p regexp t))
completion-ignore-case))
-;;;###autoload
+(defun orderless--filter (prefix regexps ignore-case table pred)
+ "Filter TABLE by PREFIX, REGEXPS and PRED.
+The matching should be case-insensitive if IGNORE-CASE is non-nil."
+ ;; If there is a regexp of the form \(?:^quoted-regexp\) then
+ ;; remove the first such and add the unquoted form to the prefix.
+ (pcase (cl-loop for r in regexps
+ thereis (orderless--anchored-quoted-regexp r))
+ (`(,regexp . ,literal)
+ (setq prefix (concat prefix literal)
+ regexps (remove regexp regexps))))
+ (let ((completion-regexp-list regexps)
+ (completion-ignore-case ignore-case))
+ (all-completions prefix table pred)))
+
(defun orderless-filter (string table &optional pred)
"Split STRING into components and find entries TABLE matching all.
The predicate PRED is used to constrain the entries in TABLE."
- (save-match-data
- (pcase-let* ((`(,prefix . ,pattern)
- (orderless--prefix+pattern string table pred))
- (completion-regexp-list
- (orderless-pattern-compiler pattern))
- (completion-ignore-case
- (orderless--ignore-case-p completion-regexp-list)))
- ;; If there is a regexp of the form \(?:^quoted-regexp\) then
- ;; remove the first such and add the unquoted form to the prefix.
- (pcase (cl-loop for r in completion-regexp-list
- thereis (orderless--anchored-quoted-regexp r))
- (`(,regexp . ,literal)
- (setq prefix (concat prefix literal)
- completion-regexp-list (delete regexp completion-regexp-list))))
- (all-completions prefix table pred))))
+ (pcase-let ((`(,prefix ,regexps ,ignore-case)
+ (orderless--compile string table pred)))
+ (orderless--filter prefix regexps ignore-case table pred)))
;;;###autoload
(defun orderless-all-completions (string table pred _point)
@@ -445,15 +447,14 @@ The predicate PRED is used to constrain the entries in
TABLE. The
matching portions of each candidate are highlighted.
This function is part of the `orderless' completion style."
(defvar completion-lazy-hilit-fn)
- (when-let ((completions (orderless-filter string table pred)))
- (pcase-let ((`(,prefix . ,pattern)
- (orderless--prefix+pattern string table pred)))
+ (pcase-let ((`(,prefix ,regexps ,ignore-case)
+ (orderless--compile string table pred)))
+ (when-let ((completions (orderless--filter prefix regexps ignore-case
table pred)))
(if (bound-and-true-p completion-lazy-hilit)
- (let ((regexps (orderless-pattern-compiler pattern)))
- (setq completion-lazy-hilit-fn
- (apply-partially #'orderless--highlight regexps
- (orderless--ignore-case-p regexps))))
- (setq completions (orderless-highlight-matches pattern completions)))
+ (setq completion-lazy-hilit-fn
+ (apply-partially #'orderless--highlight regexps ignore-case))
+ (cl-loop for str in-ref completions do
+ (setf str (orderless--highlight regexps ignore-case
(substring str)))))
(nconc completions (length prefix)))))
;;;###autoload
@@ -466,21 +467,23 @@ returns nil. In any other case it \"completes\" STRING to
itself, without moving POINT.
This function is part of the `orderless' completion style."
(catch 'orderless--many
- (let (one)
- ;; Abuse all-completions/orderless-filter as a fast search loop.
+ (pcase-let ((`(,prefix ,regexps ,ignore-case)
+ (orderless--compile string table pred))
+ (one nil))
+ ;; Abuse all-completions/orderless--filter as a fast search loop.
;; Should be almost allocation-free since our "predicate" is not
;; called more than two times.
- (orderless-filter
- string table
- ;; key/value for hash tables
- (lambda (&rest args)
- (when (or (not pred) (apply pred args))
- (setq args (car args) ;; first argument is key
- args (if (consp args) (car args) args) ;; alist
- args (if (symbolp args) (symbol-name args) args))
- (when (and one (not (equal one args)))
+ (orderless--filter
+ prefix regexps ignore-case table
+ (lambda (arg &rest val) ;; val for hash table
+ (when (or (not pred) (if val (funcall pred arg (car val)) (funcall
pred arg)))
+ ;; Normalize predicate argument
+ (setq arg (if (consp arg) (car arg) arg) ;; alist
+ arg (if (symbolp arg) (symbol-name arg) arg)) ;; symbols
+ ;; Check if there is more than a single match (= many).
+ (when (and one (not (equal one arg)))
(throw 'orderless--many (cons string point)))
- (setq one args)
+ (setq one arg)
t)))
(when one
;; Prepend prefix if the candidate does not already have the same
@@ -491,14 +494,12 @@ This function is part of the `orderless' completion
style."
;; `completion-table-with-context' calls the predicate with prefixed
;; candidates. This could be an unintended bug or oversight in
;; `completion-table-with-context'.
- (let ((prefix (car (orderless--prefix+pattern string table pred))))
- (unless (or (equal prefix "")
- (and (string-prefix-p prefix one)
- (test-completion one table pred)))
- (setq one (concat prefix one))))
- (if (equal string one)
- t ;; unique exact match
- (cons one (length one)))))))
+ (unless (or (equal prefix "")
+ (and (string-prefix-p prefix one)
+ (test-completion one table pred)))
+ (setq one (concat prefix one)))
+ (or (equal string one) ;; Return t for unique exact match
+ (cons one (length one)))))))
;;;###autoload
(add-to-list 'completion-styles-alist