@@ -6,15 +6,44 @@ import AppKit
66private var windowHoldingService = WindowHoldingService ( )
77
88public typealias SelectionCallback = ( _ selectedItems: [ Item ] ) -> Void
9+ public typealias ItemFilter = ( _ needle: String , _ haystack: [ Item ] ) -> [ Item ]
910
1011public struct FloatingFilterModule {
12+ /// Uses the default filter that scores all ``Item``s by `pattern` fuzzily, discards matches below a certain
13+ /// threshold, and sorts by score.
14+ public static func defaultFuzzyFilter(
15+ fuzziness: Double = 0.3 ,
16+ threshold: Double = 0.4
17+ ) -> ItemFilter {
18+ return { needle, haystack in
19+ let needle = needle. localizedLowercase
20+
21+ return haystack
22+ . map { ( element: $0, score: $0. title. localizedLowercase. score ( word: needle, fuzziness: fuzziness) ) }
23+ . filter { $0. score > threshold }
24+ . sorted ( by: { $0. score > $1. score } )
25+ . map { $0. element }
26+ }
27+ }
28+
1129 private init ( ) { }
1230
31+ /// - Parameters:
32+ /// - items: Filter-able items, sorted, to show in the floating filter window.
33+ /// - filterPlaceholderText: Placeholder for the FloatingFilter text field
34+ /// - windowLevel: Level to show the filter window on. Default `.floating` is intended for use
35+ /// as a utility panel.
36+ /// - closeWhenLosingFocus: Whether the filter should disappear when users e.g. activate another app
37+ /// before completing the operation. Defaults to `true` to be used as a temporary utility.
38+ /// - filter: Narrows down all filterable `items` to find `needle`. The default uses a fuzzy string
39+ /// matching algorithm.
40+ /// - selectionCallback: Output port for confirmed selections in the filter window.
1341 public static func showFilterWindow(
1442 items: [ Item ] ,
1543 filterPlaceholderText: String = NSLocalizedString ( " Filter Items " , comment: " Placeholder for the FloatingFilter text field " ) ,
1644 windowLevel: NSWindow . Level = . floating,
1745 closeWhenLosingFocus: Bool = true ,
46+ filter: @escaping ItemFilter = FloatingFilterModule . defaultFuzzyFilter ( ) ,
1847 selection selectionCallback: @escaping SelectionCallback
1948 ) {
2049 let windowController = FilterWindowController ( )
@@ -34,7 +63,10 @@ public struct FloatingFilterModule {
3463 window. makeKeyAndOrderFront ( nil )
3564 }
3665
37- let interactor = FilterInteractor ( view: windowController)
66+ let interactor = FilterInteractor (
67+ view: windowController,
68+ filter: filter
69+ )
3870 interactor. showItems ( items)
3971
4072 windowController. filterChangeDelegate = interactor
0 commit comments