diff options
Diffstat (limited to 'orderless.el')
| -rw-r--r-- | orderless.el | 110 |
1 files changed, 93 insertions, 17 deletions
diff --git a/orderless.el b/orderless.el index 7061764..67dca3a 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 |
