Skip to content

perf(search): Resolved issue with SearchKit #1688

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 21 additions & 8 deletions CodeEdit/Features/Documents/WorkspaceDocument+Find.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ 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()))
guard let mode = selectedMode.third else {
return newQuery
}

switch mode {
case .Containing:
return "*\(newQuery)*"
Expand All @@ -30,6 +31,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.
Expand All @@ -41,21 +52,23 @@ 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 = NSRegularExpression.escapedPattern(for: 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
}
}

Expand Down Expand Up @@ -175,7 +188,7 @@ extension WorkspaceDocument.SearchState {
// Attempt to create a regular expression from the provided query
guard let regex = try? NSRegularExpression(
pattern: query,
options: caseSensitive ? [] : [.caseInsensitive]
options: caseSensitive ? [] : .caseInsensitive
) else {
await setStatus(.failed(errorMessage: "Invalid regular expression."))
return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ final class FindTests: XCTestCase {

for index in 0..<fileURLs.count {
if index % 2 == 0 {
try String("Loren Ipsum").write(to: fileURLs[index], atomically: true, encoding: .utf8)
try String("Loren Ipsum.").write(to: fileURLs[index], atomically: true, encoding: .utf8)
} else {
try String("Aperiam asperiores").write(to: fileURLs[index], atomically: true, encoding: .utf8)
try String("Aperiam*asperiores").write(to: fileURLs[index], atomically: true, encoding: .utf8)
}
}

Expand Down Expand Up @@ -89,6 +89,52 @@ final class FindTests: XCTestCase {
try? FileManager.default.removeItem(at: directory)
}

func testGetSearchTerm() {
let query = "test*/Quer@#y"

searchState.selectedMode[2] = .Containing
XCTAssertEqual(searchState.getSearchTerm(query), "*test*quer*y*")

searchState.selectedMode[2] = .StartingWith
XCTAssertEqual(searchState.getSearchTerm(query), "test*quer*y*")

searchState.selectedMode[2] = .EndingWith
XCTAssertEqual(searchState.getSearchTerm(query), "*test*quer*y")

searchState.selectedMode[2] = .MatchingWord
XCTAssertEqual(searchState.getSearchTerm(query), "test*quer*y")

searchState.caseSensitive = true
XCTAssertEqual(searchState.getSearchTerm(query), "test*Quer*y")
}

func testStripSpecialCharacters() {
let string = "test!@#Query"
let strippedString = searchState.stripSpecialCharacters(from: string)
XCTAssertEqual(strippedString, "test*Query")
}

func testGetRegexPattern() {
let query = "@(test. !*#Query"

searchState.selectedMode[2] = .Containing
XCTAssertEqual(searchState.getRegexPattern(query), "@\\(test\\. !\\*#Query")

searchState.selectedMode[2] = .StartingWith
XCTAssertEqual(searchState.getRegexPattern(query), "\\b@\\(test\\. !\\*#Query")

searchState.selectedMode[2] = .EndingWith
XCTAssertEqual(searchState.getRegexPattern(query), "@\\(test\\. !\\*#Query\\b")

searchState.selectedMode[2] = .MatchingWord
XCTAssertEqual(searchState.getRegexPattern(query), "\\b@\\(test\\. !\\*#Query\\b")

// Enabling case sensitivity shouldn't affect the regex pattern because if case sensitivity is enabled,
// `NSRegularExpression.Options.caseInsensitive` is passed to `NSRegularExpression`.
searchState.caseSensitive = true
XCTAssertEqual(searchState.getRegexPattern(query), "\\b@\\(test\\. !\\*#Query\\b")
}

/// Tests the search functionality of the `WorkspaceDocument.SearchState` and `SearchIndexer`.
func testSearch() async {
let searchExpectation = XCTestExpectation(description: "Search for 'Ipsum'")
Expand Down