From c0fa2702aebad48aeb8b96957795615f8692d1ee Mon Sep 17 00:00:00 2001 From: Tom Ludwig Date: Sun, 21 Apr 2024 19:57:11 +0200 Subject: [PATCH 1/3] perf(search): Resolved issue preventing search results from displaying when queries contained special characters. --- .../Documents/WorkspaceDocument+Find.swift | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/CodeEdit/Features/Documents/WorkspaceDocument+Find.swift b/CodeEdit/Features/Documents/WorkspaceDocument+Find.swift index 4f474020c7..7af651efde 100644 --- a/CodeEdit/Features/Documents/WorkspaceDocument+Find.swift +++ b/CodeEdit/Features/Documents/WorkspaceDocument+Find.swift @@ -14,10 +14,12 @@ extension WorkspaceDocument.SearchState { /// /// - Returns: A modified search term according to the specified search mode. func getSearchTerm(_ query: String) -> String { - let newQuery = caseSensitive ? query : query.lowercased() + let newQuery = stripSpecialCharacters(from: (caseSensitive ? query : query.lowercased())) +// let newQuery = caseSensitive ? query : query.lowercased() guard let mode = selectedMode.third else { return newQuery } + switch mode { case .Containing: return "*\(newQuery)*" @@ -30,6 +32,16 @@ extension WorkspaceDocument.SearchState { } } + func stripSpecialCharacters(from string: String) -> String { + let regex = try? NSRegularExpression(pattern: "[^a-zA-Z0-9]+", options: .caseInsensitive) + return regex!.stringByReplacingMatches( + in: string, + options: [], + range: NSRange(location: 0, length: string.utf16.count), + withTemplate: "*" + ) + } + /// Generates a regular expression pattern based on the specified query and search mode. /// /// - Parameter query: The original user query string. @@ -41,21 +53,22 @@ extension WorkspaceDocument.SearchState { /// Except its using the word boundary anchor(\b) instead of the asterisk(\*). /// This is needed to highlight the search results correctly. func getRegexPattern(_ query: String) -> String { + let newQuery = query.trimmingCharacters(in: .whitespacesAndNewlines) guard let mode = selectedMode.third else { - return query + return newQuery } switch mode { case .Containing: - return "\(query)" + return "\(newQuery)" case .StartingWith: - return "\\b\(query)" + return "\\b\(newQuery)" case .EndingWith: - return "\(query)\\b" + return "\(newQuery)\\b" case .MatchingWord: - return "\\b\(query)\\b" + return "\\b\(newQuery)\\b" default: - return query + return newQuery } } @@ -172,10 +185,15 @@ extension WorkspaceDocument.SearchState { return } + var options: NSRegularExpression.Options = [.ignoreMetacharacters] + if !caseSensitive { + options.insert(.caseInsensitive) + } + // Attempt to create a regular expression from the provided query guard let regex = try? NSRegularExpression( pattern: query, - options: caseSensitive ? [] : [.caseInsensitive] + options: options ) else { await setStatus(.failed(errorMessage: "Invalid regular expression.")) return From bba4652025fc82c900d0a9b0d259fa8cb4d4dddc Mon Sep 17 00:00:00 2001 From: Tom Ludwig Date: Sat, 27 Apr 2024 23:06:56 +0200 Subject: [PATCH 2/3] Fixed tests --- .../Features/Documents/WorkspaceDocument+Find.swift | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/CodeEdit/Features/Documents/WorkspaceDocument+Find.swift b/CodeEdit/Features/Documents/WorkspaceDocument+Find.swift index 7af651efde..1a426cfd9f 100644 --- a/CodeEdit/Features/Documents/WorkspaceDocument+Find.swift +++ b/CodeEdit/Features/Documents/WorkspaceDocument+Find.swift @@ -15,7 +15,6 @@ extension WorkspaceDocument.SearchState { /// - Returns: A modified search term according to the specified search mode. func getSearchTerm(_ query: String) -> String { let newQuery = stripSpecialCharacters(from: (caseSensitive ? query : query.lowercased())) -// let newQuery = caseSensitive ? query : query.lowercased() guard let mode = selectedMode.third else { return newQuery } @@ -53,7 +52,8 @@ extension WorkspaceDocument.SearchState { /// Except its using the word boundary anchor(\b) instead of the asterisk(\*). /// This is needed to highlight the search results correctly. func getRegexPattern(_ query: String) -> String { - let newQuery = query.trimmingCharacters(in: .whitespacesAndNewlines) + let newQuery = NSRegularExpression.escapedPattern(for: query.trimmingCharacters(in: .whitespacesAndNewlines)) + guard let mode = selectedMode.third else { return newQuery } @@ -185,15 +185,10 @@ extension WorkspaceDocument.SearchState { return } - var options: NSRegularExpression.Options = [.ignoreMetacharacters] - if !caseSensitive { - options.insert(.caseInsensitive) - } - // Attempt to create a regular expression from the provided query guard let regex = try? NSRegularExpression( pattern: query, - options: options + options: caseSensitive ? [] : .caseInsensitive ) else { await setStatus(.failed(errorMessage: "Invalid regular expression.")) return From e05e528851b8e90ea6c10f0e7cdfacdacf357ca8 Mon Sep 17 00:00:00 2001 From: Tom Ludwig Date: Tue, 30 Apr 2024 22:55:37 +0200 Subject: [PATCH 3/3] Add unit test for getSearchTerm, stripSpecialCharacters and getRegexPattern --- ...kspaceDocument+SearchState+FindTests.swift | 50 ++++++++++++++++++- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/CodeEditTests/Features/Documents/WorkspaceDocument+SearchState+FindTests.swift b/CodeEditTests/Features/Documents/WorkspaceDocument+SearchState+FindTests.swift index ca3457ec57..b002063905 100644 --- a/CodeEditTests/Features/Documents/WorkspaceDocument+SearchState+FindTests.swift +++ b/CodeEditTests/Features/Documents/WorkspaceDocument+SearchState+FindTests.swift @@ -47,9 +47,9 @@ final class FindTests: XCTestCase { for index in 0..