emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/orderless ff6f57c7c8 046/204: Implement component match


From: ELPA Syncer
Subject: [elpa] externals/orderless ff6f57c7c8 046/204: Implement component matching styles
Date: Tue, 11 Jan 2022 12:58:16 -0500 (EST)

branch: externals/orderless
commit ff6f57c7c87d4b11a641bd530ed70ec7e3eb5f1d
Author: Omar Antolín <omar.antolin@gmail.com>
Commit: Omar Antolín <omar.antolin@gmail.com>

    Implement component matching styles
---
 README.org   |  74 +++++++++++++++++++++++++++++++++-------
 orderless.el | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 155 insertions(+), 29 deletions(-)

diff --git a/README.org b/README.org
index 758a3a62fb..43f483858a 100644
--- a/README.org
+++ b/README.org
@@ -1,9 +1,11 @@
 * Overview
 
 This package provides an =orderless= completion style that divides the
-pattern into space-separated components, treats each one as a regexp,
-and matches candidates that match all of the component regexps in any
-order.
+pattern into space-separated components, and matches candidates that
+match all of the components in any order. Each component can match in
+any one of several matching styles: literally, as a regexp, as an
+initialism or in the "flex" style. The regexp and initialism styles
+are enabled by default.
 
 Completion styles are used as entries in the variables
 =completion-styles= and =completion-category-overrides=, see their
@@ -20,13 +22,52 @@ on your =load-path=, and use the following configuration:
 Bug reports are highly welcome and appreciated!
 
 * Customization
+
+** Component matching styles
+
+Each component of a pattern can match in any of several matching
+styles. A matching style is simply a function from strings to strings
+that maps a component to a regexp to match against, so it is easy to
+add new matching styles. The predefined one are:
+
+- orderless-regexp :: the component is treated as a regexp that must
+  match somewhere in the candidate.
+
+  This is simply the identity function!
+
+- orderless-literal :: the component is treated as a literal string
+  that must occur in the candidate.
+
+  This is just =regexp-quote=.
+
+- orderless-initialism :: each character of the component should appear
+  as at the beginning of a word in the candidate, in order.
+
+  This maps =abc= to =\<a.*\<b.*\c=.
+
+- orderless-flex :: the characters of the component should appear in
+  that order in the candidate, but not necessarily consecutively.
+
+  This maps =abc= to =a.*b.*c=.
+
+- orderless-prefixes :: the component is split on hyphens and slashes
+  and each piece must be a word prefix in the candidate, occurring in
+  that order.
+
+  This is similar to the built-in =partial-completion= completion-style.
+  For example =re-re= matches =query-replace-regexp= and =recode-region=.
+
+The variable =orderless-component-matching-style= should be set to a
+list of the desired styles to use. By default it enables the regexp
+and initialism styles.
+
 ** Component separator regexp
 
-The regexp components by default are space-separated, but this is
+The pattern components by default are space-separated, but this is
 controlled by the variable =orderless-regexp-separator=, which should be
 set to a regexp that matches the desired component separator. The
 default value matches a sequence of spaces. It may be useful to add
-hypens or slashes (or both), to match symbols or file paths,
+hyphens or slashes (or both), to match symbols or file paths,
 respectively.
 
 If you are implementing a command for which you know you want a
@@ -58,6 +99,8 @@ being used, of course.
 
 * Related packages
 
+** Ivy and Helm
+
 The well-known and hugely powerful completion frameworks 
[[https://github.com/abo-abo/swiper][Ivy]] and 
[[https://github.com/emacs-helm/helm][Helm]]
 also provide for matching space-separated component regexps in any
 order. In Ivy, this is done with the =ivy--regex-ignore-order= matcher.
@@ -69,9 +112,10 @@ Icomplete completion UI, while both of those provide their 
own
 completion UI (and many other cool features!).
 
 It is worth pointing out that Helm does provide its multi pattern
-matching as a completion style which could be used with Icomplete! So,
-Icomplete users could, instead of using this package, instead install
-Helm and configure Icomplete to use it as follows:
+matching as a completion style which could be used with Icomplete!
+(Ivy does not.) So, Icomplete users could, instead of using this
+package, instead install Helm and configure Icomplete to use it as
+follows:
 
 #+begin_src emacs-lisp
   (require 'helm)
@@ -82,7 +126,13 @@ Helm and configure Icomplete to use it as follows:
 (Of course, if you install Helm, you probably might as well use the
 Helm UI in =helm-mode= rather than using Icomplete.)
 
-The combination of [[https://github.com/raxod502/selectrum][Selectrum]] and 
[[https://github.com/raxod502/prescient.el][prescient.el]] also provides 
matching
-of space-separated components in any order, but each component can be
-matched not only as a regexp, but also a literal string or an
-initialism, so the set of candidates returned may be larger.
+** Prescient
+
+The [[https://github.com/raxod502/prescient.el][prescient.el]] library also 
provides matching of space-separated
+components in any order and it can be used with either the 
[[https://github.com/raxod502/selectrum][Selectrum]]
+or [[https://github.com/abo-abo/swiper][Ivy]] completion UIs (it does not 
provide a completion-style that
+could be used with Emacs' default completion UI or with Icomplete).
+The components can be matched literally, as regexps, as initialisms or
+in the flex style (called "fuzzy" in prescient). In addition to
+matching, =prescient.el= also provides sorting of candidates (=orderless=
+leaves that up to the candidate source and the completion UI).
diff --git a/orderless.el b/orderless.el
index 7061764fad..67dca3aabc 100644
--- a/orderless.el
+++ b/orderless.el
@@ -4,7 +4,7 @@
 
 ;; Author: Omar Antolín Camarena <omar@matem.unam.mx>
 ;; Keywords: extensions
-;; Version: 0.1
+;; Version: 0.3
 ;; Homepage: https://github.com/oantolin/orderless
 ;; Package-Requires: ((emacs "24.3"))
 
@@ -24,25 +24,32 @@
 ;;; Commentary:
 
 ;; This package provides an `orderless' completion style that divides
-;; the pattern into components chunks (space-separated by default),
-;; treats each on as a regexp, and matches candidates that match all of
-;; the regexps in any order.
-;;
+;; the pattern into components (space-separated by default), and
+;; matches candidates that match all of the components in any order.
+
 ;; Completion styles are used as entries in the variables
 ;; `completion-styles' and `completion-category-overrides', see their
 ;; documentation.
-;;
+
 ;; To use this completion style you can use the following minimal
 ;; configuration:
-;;
+
 ;; (setq completion-styles '(orderless))
-;;
+
 ;; You can customize the `orderless-regexp-separator' to decide how
 ;; the input pattern is split into component regexps.  The default
 ;; splits on spaces.  You might want to add hyphens and slashes, for
 ;; example, to ease completion of symbols and file paths,
 ;; respectively.
 
+;; Each component can match in any one of several matching styles:
+;; literally, as a regexp, as an initialism, in the flex style, or as
+;; word prefixes.  It is easy to add new styles: they are functions
+;; from strings to strings that map a component to a regexp to match
+;; against.  The variable `orderless-component-matching-styles' lists
+;; the matching styles to be used for components, by default it allows
+;; regexp and initialism matching.
+
 ;;; Code:
 
 (require 'cl-lib)
@@ -101,20 +108,86 @@ component regexps."
   :type '(vector 'face)
   :group 'orderless)
 
+(defcustom orderless-component-matching-styles
+  '(orderless-regexp orderless-initialism)
+  "List of allowed component matching styles.
+If this variable is nil, regexp matching is assumed.
+
+A matching style is simply a function from strings to strings
+that takes a component to a regexp to match against.  If the
+resulting regexp has no capturing groups, the entire match is
+highlighted, otherwise just the captured groups are."
+  :type '(set
+          (const :tag "Regexp" orderless-regexp)
+          (const :tag "Literal" orderless-literal)
+          (const :tag "Initialism" orderless-initialism)
+          (const :tag "Flex" orderless-flex)
+          (const :tag "Prefixes" orderless-prefixes)
+          (function :tag "Custom matching style"))
+  :group 'orderless)
+
+(defalias 'orderless-regexp #'identity
+  "Match a component as a regexp.
+This is simply the identity function.")
+
+(defalias 'orderless-literal #'regexp-quote
+  "Match a component as a literal string.
+This is simply `regexp-quote'.")
+
+(defun orderless--anything-between (rxs)
+  "Return a regexp to match the rx-regexps RXS with .* in between."
+  (rx-to-string
+   `(seq ,@(cl-loop for (sexp . more) on rxs
+                    collect `(group ,sexp)
+                    when more collect `(zero-or-more nonl)))))
+
+(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."
+  (orderless--anything-between
+   (cl-loop for char across component collect char)))
+
+(defun orderless-initialism (component)
+  "Match a component as an initialism.
+This means the characters in COMPONENT must occur in the
+candidate, in that order, at the beginning of words."
+  (orderless--anything-between
+   (cl-loop for char across component collect `(seq word-start ,char))))
+
+(defun orderless-prefixes (component)
+  "Match a component as slash-or-hyphen-separated word prefixes.
+The COMPONENT is split on slashes and hyphens, and each piece
+must match a prefix of a word in the candidate.  This is similar
+to the `partial-completion' completion style."
+  (orderless--anything-between
+   (cl-loop for prefix in (split-string component "[/-]")
+            collect `(seq word-start ,prefix))))
+
 (defun orderless--highlight-matches (regexps string)
-    "Highlight matches of REGEXPS in STRING.
+    "Highlight a match of each of the REGEXPS in STRING.
 Warning: only call this if you know all REGEXPs match STRING!"
     (setq string (copy-sequence string))
     (cl-loop with n = (length orderless-match-faces)
              for regexp in regexps and i from 0 do
              (string-match regexp string)
-             (font-lock-prepend-text-property
-              (match-beginning 0)
-              (match-end 0)
-              'face (aref orderless-match-faces (mod i n))
-              string))
+             (cl-loop
+              for (x y) on (or (cddr (match-data)) (match-data)) by #'cddr
+              when x do
+              (font-lock-prepend-text-property
+               x y
+               'face (aref orderless-match-faces (mod i n))
+               string)))
     string)
 
+(defun orderless--component-regexp (component)
+  "Build regexp to match COMPONENT.
+Consults `orderless-component-matching-styles' to decide what to
+match."
+  (rx-to-string
+   `(or ,@(cl-loop for style in orderless-component-matching-styles
+                   collect `(regexp ,(funcall style component))))))
+
 (defun orderless-all-completions (string table pred _point)
   "Split STRING into components and find entries TABLE matching all.
 The predicate PRED is used to constrain the entries in TABLE.
@@ -123,10 +196,13 @@ This function is part of the `orderless' completion 
style."
       (save-match-data
         (let* ((limit (car (completion-boundaries string table pred "")))
                (prefix (substring string 0 limit))
+               (components (split-string (substring string limit)
+                                         orderless-regexp-separator
+                                         t))
                (completion-regexp-list ; used by all-completions!!!
-                (split-string (substring string limit)
-                              orderless-regexp-separator
-                              t))
+                (if orderless-component-matching-styles
+                    (mapcar #'orderless--component-regexp components)
+                  components))
                (completions (all-completions prefix table pred)))
           (when completions
             (when minibuffer-completing-file-name



reply via email to

[Prev in Thread] Current Thread [Next in Thread]