Skip to content

Commit

Permalink
Only add properties for prescient-sort-full-matches-first to the fi…
Browse files Browse the repository at this point in the history
…rst candidate.

Only add properties to the first candidate, and search for the
properties in the candidates list. This should be better than what we
do now, which is to propertize every candidate and later get the
properties from the first candidate in the list.

For N candidates, the old way is always

    (propertize N) + (search 1) + (sort N)

and the new way is

    (propertize 1) + (search (N - x)) + (sort N)

where x is greater than or equal to 0. Assuming that
`get-text-property` is no worse than `propertize` (which seems true in
testing), the new way is never worse than the old way, and should
usually be better.

Add function `prescient--get-sort-info`, to complement
`prescient--add-sort-info`.
  • Loading branch information
okamsn committed Jul 8, 2023
1 parent 822481e commit 6b7eda0
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 23 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog].

## Unreleased

### Internal Changes

* `prescient-filter` now only propertizes the first returned candidate
for use with `prescient-sort-full-matches-first` ([#148]). Custom
sorting functions using this data should be changed to search the
candidates for the properties, as in `prescient--get-sort-info`.

[#148]: https://github.com/radian-software/prescient.el/pull/148

## 6.1 (released 2022-12-16)
### New features
* Add package `vertico-prescient`, which integrates prescient.el with
Expand Down
66 changes: 43 additions & 23 deletions prescient.el
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ INPUT contains uppercase letters."
prescient-use-case-folding))

(defun prescient--add-sort-info (candidates regexps ignore-case)
"Propertize all candidates in CANDIDATES to save data.
"Propertize the first candidate in CANDIDATES to save data.
REGEXPS are the regexps used by filtering. IGNORE-CASE is whether
case was ignored. These are stored as the text property
Expand All @@ -464,16 +464,32 @@ This information is used by the function
`prescient-sort-full-matches-first'."
(if (null candidates)
nil
;; We need to propertize all of the candidates, since some UIs
;; might rearrange candidates before we can sort them. For
;; example, Company will sort CAPF candidates that don't have a
;; specified sorting function, which moves them around before
;; Some UIs might rearrange candidates before we can sort them.
;; For example, Company will sort CAPF candidates that don't have
;; a specified sorting function, which moves them around before
;; passing them to the Company Prescient transformer that applies
;; our own sorting.
(cl-loop for cand in candidates
collect (propertize cand
'prescient-regexps regexps
'prescient-ignore-case ignore-case))))
(cons (propertize (car candidates)
'prescient-regexps regexps
'prescient-ignore-case ignore-case)
(cdr candidates))))

(defun prescient--get-sort-info (candidates)
"Return a property list of properties added by `prescient-filter'.
`prescient-filter' adds properties to the CANDIDATES that it
filtered for use by the function `prescient-sort-full-matches-first'.
If the properties aren't found, such as when the candidates were
filtered using a different completion method, then the values in
the property list are nil."
(cl-loop for cand in candidates
until (get-text-property 0 'prescient-regexps cand)
finally return
`(prescient-regexps
,(get-text-property 0 'prescient-regexps cand)
prescient-ignore-case
,(get-text-property 0 'prescient-ignore-case cand))))

(defun prescient--highlight-matches (input candidates)
"According to INPUT, highlight the matched sections in CANDIDATES.
Expand Down Expand Up @@ -906,25 +922,29 @@ This function will always sort candidates using the function
using the function `prescient-sort-full-matches-first'.
This function checks for the properties `prescient-regexps' and
`prescient-ignore-case' on the first candidate in
CANDIDATES (though they are stored on all candidates filtered by
`prescient-ignore-case' on any candidate in CANDIDATES (though
they are stored on the first candidate returned by
`prescient-filter'). These properties are used for implementing
the user option `prescient-sort-full-matches-first'."
(if (null candidates)
nil
(let ((regexps (get-text-property 0 'prescient-regexps
(car candidates)))
(ignore-case (get-text-property 0 'prescient-ignore-case
(car candidates)))
(sorted (prescient-sort candidates)))
;; `prescient-filter' adds the properties needed for
;; `prescient-sort-full-matches-first' to the first candidate in
;; the list it returns. If we're receiving the filtered candidates
;; directly (so, not in `company-prescient-transformer') then we
;; should be checking for them before running `prescient-sort',
;; which destructively modifies CANDIDATES.
(let ((regexps)
(ignore-case))
(when prescient-sort-full-matches-first
(setq sorted (prescient-sort-full-matches-first
sorted regexps ignore-case)))
;; Since we propertize all candidates during `prescient-filter',
;; we don't need to worry about re-arranging candidates here
;; for whatever comes after, such as the Company Prescient
;; transformer.
sorted)))
(let ((props (prescient--get-sort-info candidates)))
(setq regexps (plist-get props 'prescient-regexps)
ignore-case (plist-get props 'prescient-ignore-case))))
(thread-first
candidates
(prescient-sort)
;; If `regexps' is nil, this just returns the input.
(prescient-sort-full-matches-first regexps ignore-case)))))

;;;;; Filtering functions

Expand Down

0 comments on commit 6b7eda0

Please sign in to comment.