-
Notifications
You must be signed in to change notification settings - Fork 1
/
filter-preprocessor.lisp
71 lines (63 loc) · 3.06 KB
/
filter-preprocessor.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
;;;; SPDX-FileCopyrightText: Atlas Engineer LLC
;;;; SPDX-License-Identifier: BSD-3-Clause
(in-package :prompter)
(defun smart-case-test (string)
(if (str:downcasep string)
#'string-equal
#'string=))
(defun find-exactly-matching-substrings (input suggestion-match-data
&key (substring-length 2))
"Return the list of input substrings that match at least one suggestion.
The substrings must be SUBSTRING-LENGTH characters long or more."
(let ((input-strings (delete-if (lambda (s) (< (length s) substring-length))
(str:split " " input :omit-nulls t))))
(when input-strings
(delete-duplicates
(loop for match-datum in suggestion-match-data
append (remove-if
(lambda (i)
(not (search i match-datum :test (smart-case-test i))))
input-strings))
:test #'string=))))
;; TODO: Disambiguate naming of `delete-inexact-matches' and `filter-exact-matches'?
(export-always 'delete-inexact-matches)
(defun delete-inexact-matches (suggestions source input)
"Destructively filter out non-exact matches from SUGGESTIONS.
Return the resulting list.
If any input substring matches exactly (but not necessarily a whole word),
then all suggestions that are not exactly matched by at least one substring are removed.
Suitable as a `source' `filter-preprocessor'."
(unless (str:empty? input)
(let ((exactly-matching-substrings (find-exactly-matching-substrings
input
(mapcar (lambda (suggestion)
(ensure-match-data-string suggestion source))
suggestions))))
(when exactly-matching-substrings
(setf suggestions
(delete-if (lambda (suggestion)
(not (loop for i in exactly-matching-substrings
always (search i (match-data suggestion)
:test (smart-case-test i)))))
suggestions)))))
suggestions)
(export-always 'filter-exact-matches)
(defun filter-exact-matches (suggestions source input)
"Return only SUGGESTIONS that match all the words in INPUT."
(if (str:empty? input)
suggestions
(let ((words (sera:words input)))
(delete-if (lambda (suggestion)
(notevery (lambda (sub) (search sub (ensure-match-data-string suggestion source)
:test (smart-case-test sub)))
words))
suggestions))))
(export-always 'filter-exact-match)
(defun filter-exact-match (suggestions source input)
"Return only SUGGESTIONS that are identical to INPUT"
(declare (ignore source))
(if (str:empty? input)
suggestions
(delete-if (lambda (suggestion)
(not (string-equal input (attributes-default suggestion))))
suggestions)))