Skip to content

Commit

Permalink
Support completion-lazy-hilit and completion-lazy-hilit-fn for Em…
Browse files Browse the repository at this point in the history
…acs 30. (radian-software#153)

This feature allows highlighting to occur later instead of being
performed by the completion style immediately.

- Move logic for highlighting a single candidate from
  `prescient--highlight-matches` to `prescient--highlight-candidate`.

- Rename `prescient--highlight-matches` to
  `prescient--highlight-candidates`, which now applies the new
  function to a list of candidates.
  - Keep this function to support
    `prescient-completion-highlight-matches`, which we're also
    keeping.

See:
- Prescient issue radian-software#152
  (radian-software#152)

- Emacs bug #47711
  (https://debbugs.gnu.org/cgi/bugreport.cgi?bug=47711)

- Emacs commit dfffb91a70532ac0021648ba692336331cbe0499
  (https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=dfffb91a70532ac0021648ba692336331cbe0499),

- Vertico commit b11040e1e9c1a4e5178800a0d0925aeeb72dd027
  (minad/vertico@b11040e)

- This Prescient PR radian-software#153
  (radian-software#153).
  • Loading branch information
okamsn authored Dec 5, 2023
1 parent 707c25c commit b701032
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 33 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog].

## Unreleased
### Enhancements
* The completion style now supports lazy highlighting via
`completion-lazy-hilit` and `completion-lazy-hilit-fn`, new in Emacs
30 and already supported by some completion UIs ([#152], [#153]).

[#152]: https://github.com/radian-software/prescient.el/issues/152
[#153]: https://github.com/radian-software/prescient.el/pull/153

## 6.2 (released 2023-11-23)
### Features
* New user option `prescient-tiebreaker` which can be used to change
Expand Down
91 changes: 60 additions & 31 deletions prescient.el
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,9 @@ contains no upper-case letters."
(defcustom prescient-completion-highlight-matches t
"Whether the `prescient' completion style should highlight matches.
If `completion-lazy-hilit' is bound and non-nil, then this user
option is ignored in favor of that variable.
See also the faces `prescient-primary-highlight' and
`prescient-secondary-highlight'."
:type 'boolean)
Expand Down Expand Up @@ -522,37 +525,43 @@ filtered for use by the function `prescient-sort-full-matches-first'."
;; just return all properties here.
finally return props))

(defun prescient--highlight-matches (input candidates)
(defun prescient--highlight-candidate (regexps case-fold candidate)
"Highlight text matching REGEXPS and considering CASE-FOLD in CANDIDATE.
Returns a propertized CANDIDATE."
(setq candidate (copy-sequence candidate))
(prog1 candidate
(let ((case-fold-search case-fold))
(save-match-data
(dolist (regexp regexps)
(when (string-match regexp candidate)
(font-lock-prepend-text-property
(match-beginning 0) (match-end 0)
'face 'prescient-primary-highlight
candidate)
(cl-loop
for (start end)
on (cddr (match-data))
by #'cddr
do (when (and start end)
(font-lock-prepend-text-property
start end
'face 'prescient-secondary-highlight
candidate)))))))))

(defun prescient--highlight-candidates (input candidates)
"According to INPUT, highlight the matched sections in CANDIDATES.
INPUT is the string that was used to generate a list of regexps
for filtering. CANDIDATES is the list of filtered candidates,
which should be a list of strings.
Return a list of propertized CANDIDATES."
(let ((regexps (prescient-filter-regexps input 'with-group))
(case-fold-search (prescient-ignore-case-p input)))
(save-match-data
(mapcar
(lambda (candidate)
(setq candidate (copy-sequence candidate))
(prog1 candidate
(dolist (regexp regexps)
(when (string-match regexp candidate)
(font-lock-prepend-text-property
(match-beginning 0) (match-end 0)
'face 'prescient-primary-highlight
candidate)
(cl-loop
for (start end)
on (cddr (match-data))
by #'cddr
do (when (and start end)
(font-lock-prepend-text-property
start end
'face 'prescient-secondary-highlight
candidate)))))))
candidates))))
(cl-loop with regexps = (prescient-filter-regexps input 'with-group)
and case-fold-search = (prescient-ignore-case-p input)
for cand in candidates
collect (prescient--highlight-candidate regexps case-fold-search
cand)))

;;;; Regexp Builders

Expand Down Expand Up @@ -983,6 +992,9 @@ REGEXPS."
;; completion style. This feature is based on Orderless.el.
;; See: https://github.com/oantolin/orderless

(defvar completion-lazy-hilit)
(defvar completion-lazy-hilit-fn)

;;;;; Sorting functions

;;;###autoload
Expand Down Expand Up @@ -1032,15 +1044,32 @@ See the function `all-completions' for more information.
This function returns a list of completions whose final `cdr' is
the length of the prefix string used for completion (which might
be all or just part of STRING)."
be all or just part of STRING).
When `completion-lazy-hilit' is bound and non-nil, then this
function sets `completion-lazy-hilit-fn'. Otherwise, if
`prescient-completion-highlight-matches' is non-nil, this
function propertizes all of the returned completions using the
face `prescient-primary-highlight' and the face
`prescient-secondary-highlight'."
;; `point' is a required argument, but unneeded here.
(when-let ((completions (prescient-filter string table pred)))
(pcase-let ((`(,prefix . ,pattern)
(prescient--prefix-and-pattern string table pred)))
(nconc (if prescient-completion-highlight-matches
(prescient--highlight-matches pattern completions)
completions)
(length prefix)))))
(pcase-let* ((`(,prefix . ,pattern)
(prescient--prefix-and-pattern string table pred))
(maybe-highlighted
(cond
((bound-and-true-p completion-lazy-hilit)
(setq completion-lazy-hilit-fn
(apply-partially
#'prescient--highlight-candidate
(prescient-filter-regexps pattern 'with-group)
(prescient-ignore-case-p pattern)))
completions)
(prescient-completion-highlight-matches
(prescient--highlight-candidates pattern completions))
(t
completions))))
(nconc maybe-highlighted (length prefix)))))

;;;###autoload
(defun prescient-try-completion (string table &optional pred point)
Expand Down
4 changes: 2 additions & 2 deletions selectrum-prescient.el
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ For use on `selectrum-candidate-selected-hook'."
(setq selectrum-refine-candidates-function
#'selectrum-prescient--refine)
(setq selectrum-highlight-candidates-function
#'prescient--highlight-matches)
#'prescient--highlight-candidates)
(define-key selectrum-minibuffer-map
(kbd "M-s") prescient-toggle-map)
(add-hook 'prescient--toggle-refresh-functions
Expand All @@ -147,7 +147,7 @@ For use on `selectrum-candidate-selected-hook'."
(setq selectrum-refine-candidates-function
selectrum-prescient--old-refine-function))
(when (eq selectrum-highlight-candidates-function
#'prescient--highlight-matches)
#'prescient--highlight-candidates)
(setq selectrum-highlight-candidates-function
selectrum-prescient--old-highlight-function))
(when (equal (lookup-key selectrum-minibuffer-map (kbd "M-s"))
Expand Down

0 comments on commit b701032

Please sign in to comment.