From 860a10222a1a6be3ea87a77d34d09cd0e2dfd422 Mon Sep 17 00:00:00 2001 From: Daniel Mendler Date: Thu, 5 Sep 2024 11:13:00 +0200 Subject: orderless-expand-prefix: Support the values `prefix`, `substring` and `nil` Using `completion-substring-try-completion` can be costly in comparison to prefix completion only via `try-completion`, in particular in the context of timer-based auto completion. As a compromise, default to `prefix` completion only. Performance should not be affected, while expansion is still provided. Depending on preference the expansion setting can be escalated to `substring` or even disabled, in case the restrictive Orderless (non-)expansion behavior is preferred. --- orderless.el | 86 ++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 46 insertions(+), 40 deletions(-) diff --git a/orderless.el b/orderless.el index 187fd38..4e731fb 100644 --- a/orderless.el +++ b/orderless.el @@ -212,14 +212,17 @@ is determined by the values of `completion-ignore-case', `read-buffer-completion-ignore-case', as usual for completion." :type 'boolean) -(defcustom orderless-expand-substring t +(defcustom orderless-expand-substring 'prefix "Whether to perform literal substring expansion. -If enabled, `orderless-try-completion' will first attempt literal -substring expansion via `completion-substring-try-completion'. -Otherwise expansion is only performed for single unique matches. This configuration option affects the behavior of some completion -interfaces when pressing TAB." - :type 'boolean) +interfaces when pressing TAB. If enabled `orderless-try-completion' +will first attempt literal substring expansion. If disabled, +expansion is only performed for single unique matches. For +performance reasons only `prefix' expansion is enabled by default. +Set the variable to `substring' for full substring expansion." + :type '(choice (const :tag "No expansion" nil) + (const :tag "Substring" substring) + (const :tag "Prefix (efficient)" prefix))) ;;; Matching styles @@ -563,40 +566,43 @@ match, it completes to that match. If there are no matches, it returns nil. In any other case it \"completes\" STRING to itself, without moving POINT. This function is part of the `orderless' completion style." - (or (and orderless-expand-substring - (completion-substring-try-completion string table pred point)) - (catch 'orderless--many - (pcase-let ((`(,prefix ,regexps ,ignore-case ,pred) - (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 - prefix regexps ignore-case table - (orderless--predicate-normalized-and - pred - (lambda (arg) - ;; 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 arg) - t))) - (when one - ;; Prepend prefix if the candidate does not already have the same - ;; prefix. This workaround is needed since the predicate may either - ;; receive an unprefixed or a prefixed candidate as argument. Most - ;; completion tables consistently call the predicate with unprefixed - ;; candidates, for example `completion-file-name-table'. In contrast, - ;; `completion-table-with-context' calls the predicate with prefixed - ;; candidates. This could be an unintended bug or oversight in - ;; `completion-table-with-context'. - (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)))))))) + (or + (pcase orderless-expand-substring + ('nil nil) + ('prefix (completion-emacs21-try-completion string table pred point)) + (_ (completion-substring-try-completion string table pred point))) + (catch 'orderless--many + (pcase-let ((`(,prefix ,regexps ,ignore-case ,pred) + (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 + prefix regexps ignore-case table + (orderless--predicate-normalized-and + pred + (lambda (arg) + ;; 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 arg) + t))) + (when one + ;; Prepend prefix if the candidate does not already have the same + ;; prefix. This workaround is needed since the predicate may either + ;; receive an unprefixed or a prefixed candidate as argument. Most + ;; completion tables consistently call the predicate with unprefixed + ;; candidates, for example `completion-file-name-table'. In contrast, + ;; `completion-table-with-context' calls the predicate with prefixed + ;; candidates. This could be an unintended bug or oversight in + ;; `completion-table-with-context'. + (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 -- cgit v1.0