From 62664e1097a14c7fd361fd549488591b1f5bbd28 Mon Sep 17 00:00:00 2001 From: Wouter01 Date: Tue, 27 Jun 2023 00:07:20 +0200 Subject: [PATCH] performance improvements to fuzzysearch Signed-off-by: Wouter01 --- .../QuickOpen/ViewModels/FuzzySearch.swift | 32 ++++++++----------- .../ViewModels/QuickOpenViewModel.swift | 16 ++++++---- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/CodeEdit/Features/QuickOpen/ViewModels/FuzzySearch.swift b/CodeEdit/Features/QuickOpen/ViewModels/FuzzySearch.swift index aaed2ddd06..b11884ac07 100644 --- a/CodeEdit/Features/QuickOpen/ViewModels/FuzzySearch.swift +++ b/CodeEdit/Features/QuickOpen/ViewModels/FuzzySearch.swift @@ -6,6 +6,7 @@ // import Foundation +import CollectionConcurrencyKit enum FuzzySearch { /// Searches an array of view models for occurrences of a fuzzy search query. @@ -20,19 +21,14 @@ enum FuzzySearch { /// - query: A `String` value representing the fuzzy search query. /// - urls: An array of `URL`s, each representing a file, to search within. /// - Returns: An array of `URL`s that match the fuzzy search query, sorted by score. - static func search(query: String, in urls: [URL]) -> [URL] { - let filteredResult = urls.filter { url -> Bool in - let nameScore = score(query: query, url: url) - return nameScore > 0.0 - } - - let sortedResult = filteredResult.sorted { url1, url2 -> Bool in - let nameScore1 = score(query: query, url: url1) - let nameScore2 = score(query: query, url: url2) - return nameScore1 > nameScore2 - } - - return sortedResult + static func search(query: String, in urls: [URL]) async -> [URL] { + let queryTokens = query.lowercased().components(separatedBy: .whitespacesAndNewlines) + + return await urls + .concurrentMap { (url: $0, score: score(tokens: queryTokens, url: $0)) } + .filter { $0.score > .zero } + .sorted { $0.score > $1.score } + .map(\.url) } /// Calculates the score of the fuzzy search query against a text string. @@ -47,13 +43,11 @@ enum FuzzySearch { /// - query: A `String` value representing the fuzzy search query. /// - url: A `URL` value representing the filePath to search within. /// - Returns: A `Double` value representing the calculated score. - private static func score(query: String, url: URL) -> Double { - let query = query.lowercased() + private static func score(tokens: [String], url: URL) -> Double { let text = url.lastPathComponent.lowercased() - let queryTokens = query.split(separator: " ") var score: Double = 0.0 - for token in queryTokens { + for token in tokens { let ranges = text.ranges(of: token) if !ranges.isEmpty { let tokenScore = Double(token.count) / Double(text.count) @@ -64,9 +58,9 @@ enum FuzzySearch { } if let date = getLastModifiedDate(for: url.path) { - return (score / Double(queryTokens.count)) * Double(calculateDateScore(for: date)) + return (score / Double(tokens.count)) * Double(calculateDateScore(for: date)) } else { - return (score / Double(queryTokens.count)) + return (score / Double(tokens.count)) } } diff --git a/CodeEdit/Features/QuickOpen/ViewModels/QuickOpenViewModel.swift b/CodeEdit/Features/QuickOpen/ViewModels/QuickOpenViewModel.swift index 0d695b3476..1fdc4c2f60 100644 --- a/CodeEdit/Features/QuickOpen/ViewModels/QuickOpenViewModel.swift +++ b/CodeEdit/Features/QuickOpen/ViewModels/QuickOpenViewModel.swift @@ -54,14 +54,16 @@ final class QuickOpenViewModel: ObservableObject { } /// sorts the filtered filePaths with the FuzzySearch - let orderedFiles = FuzzySearch.search(query: self.openQuicklyQuery, in: filteredFiles) - .map { url in - CEWorkspaceFile(url: url, children: nil) - } + Task { + let orderedFiles = await FuzzySearch.search(query: self.openQuicklyQuery, in: filteredFiles) + .map { url in + CEWorkspaceFile(url: url, children: nil) + } - DispatchQueue.main.async { - self.openQuicklyFiles = orderedFiles - self.isShowingOpenQuicklyFiles = !self.openQuicklyFiles.isEmpty + DispatchQueue.main.async { + self.openQuicklyFiles = orderedFiles + self.isShowingOpenQuicklyFiles = !self.openQuicklyFiles.isEmpty + } } } }