Skip to content

Commit 4c22bc3

Browse files
Merge branch 'main' into lsp-install
2 parents 80d16d9 + f52062e commit 4c22bc3

File tree

50 files changed

+278
-4984
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+278
-4984
lines changed

.github/scripts/test_app.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ elif [ $1 = "arm" ]; then
88
ARCH="arm64"
99
fi
1010

11+
echo "Building with Xcode: $(xcodebuild -version)"
1112
echo "Building with arch: ${ARCH}"
1213
echo "SwiftLint Version: $(swiftlint --version)"
1314

CodeEdit.xcodeproj/project.pbxproj

Lines changed: 123 additions & 4341 deletions
Large diffs are not rendered by default.

CodeEdit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist

Lines changed: 0 additions & 8 deletions
This file was deleted.

CodeEdit.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings

Lines changed: 0 additions & 8 deletions
This file was deleted.

CodeEdit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

CodeEdit.xcodeproj/xcshareddata/xcschemes/CodeEdit.xcscheme

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Scheme
3-
LastUpgradeVersion = "1540"
3+
LastUpgradeVersion = "1620"
44
version = "1.7">
55
<BuildAction
66
parallelizeBuildables = "YES"

CodeEdit/Features/CodeEditExtension/README.md

Lines changed: 0 additions & 3 deletions
This file was deleted.

CodeEdit/Features/Documents/WorkspaceDocument/WorkspaceDocument+Find.swift

Lines changed: 60 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
import Foundation
99

10+
extension WorkspaceDocument.SearchState: @unchecked Sendable {}
11+
1012
extension WorkspaceDocument.SearchState {
1113
/// Creates a search term based on the given query and search mode.
1214
///
@@ -94,9 +96,6 @@ extension WorkspaceDocument.SearchState {
9496
}
9597

9698
let searchQuery = getSearchTerm(query)
97-
98-
// The regexPattern is only used for the evaluateFile function
99-
// to ensure that the search terms are highlighted correctly
10099
let regexPattern = getRegexPattern(query)
101100

102101
guard let indexer = indexer else {
@@ -105,24 +104,32 @@ extension WorkspaceDocument.SearchState {
105104
}
106105

107106
let asyncController = SearchIndexer.AsyncManager(index: indexer)
108-
109107
let evaluateResultGroup = DispatchGroup()
110108
let evaluateSearchQueue = DispatchQueue(label: "app.codeedit.CodeEdit.EvaluateSearch")
111109

112110
let searchStream = await asyncController.search(query: searchQuery, 20)
113111
for try await result in searchStream {
114112
for file in result.results {
113+
let fileURL = file.url
114+
let fileScore = file.score
115+
let capturedRegexPattern = regexPattern
116+
115117
evaluateSearchQueue.async(group: evaluateResultGroup) {
116118
evaluateResultGroup.enter()
117-
Task {
118-
var newResult = SearchResultModel(file: CEWorkspaceFile(url: file.url), score: file.score)
119-
await self.evaluateFile(query: regexPattern, searchResult: &newResult)
120-
121-
// Check if the new result has any line matches.
122-
if !newResult.lineMatches.isEmpty {
123-
// The function needs to be called because,
124-
// we are trying to modify the array from within a concurrent context.
125-
self.appendNewResultsToTempResults(newResult: newResult)
119+
Task { [weak self] in
120+
guard let self else {
121+
evaluateResultGroup.leave()
122+
return
123+
}
124+
125+
let result = await self.evaluateSearchResult(
126+
fileURL: fileURL,
127+
fileScore: fileScore,
128+
regexPattern: capturedRegexPattern
129+
)
130+
131+
if let result = result {
132+
await self.appendNewResultsToTempResults(newResult: result)
126133
}
127134
evaluateResultGroup.leave()
128135
}
@@ -131,33 +138,33 @@ extension WorkspaceDocument.SearchState {
131138
}
132139

133140
evaluateResultGroup.notify(queue: evaluateSearchQueue) {
134-
self.setSearchResults()
141+
Task { @MainActor [weak self] in
142+
self?.setSearchResults()
143+
}
135144
}
136145
}
137146

138147
/// Appends a new search result to the temporary search results array on the main thread.
139148
///
140149
/// - Parameters:
141150
/// - newResult: The `SearchResultModel` to be appended to the temporary search results.
151+
@MainActor
142152
func appendNewResultsToTempResults(newResult: SearchResultModel) {
143-
DispatchQueue.main.async {
144-
self.tempSearchResults.append(newResult)
145-
}
153+
self.tempSearchResults.append(newResult)
146154
}
147155

148156
/// Sets the search results by updating various properties on the main thread.
149157
/// This function updates `findNavigatorStatus`, `searchResult`, `searchResultCount`, and `searchResultsFileCount`
150158
/// and sets the `tempSearchResults` to an empty array.
151159
/// - Important: Call this function when you are ready to
152160
/// display or use the final search results.
161+
@MainActor
153162
func setSearchResults() {
154-
DispatchQueue.main.async {
155-
self.searchResult = self.tempSearchResults.sorted { $0.score > $1.score }
156-
self.searchResultsCount = self.tempSearchResults.map { $0.lineMatches.count }.reduce(0, +)
157-
self.searchResultsFileCount = self.tempSearchResults.count
158-
self.findNavigatorStatus = .found
159-
self.tempSearchResults = []
160-
}
163+
self.searchResult = self.tempSearchResults.sorted { $0.score > $1.score }
164+
self.searchResultsCount = self.tempSearchResults.map { $0.lineMatches.count }.reduce(0, +)
165+
self.searchResultsFileCount = self.tempSearchResults.count
166+
self.findNavigatorStatus = .found
167+
self.tempSearchResults = []
161168
}
162169

163170
/// Evaluates a search query within the content of a file and updates
@@ -183,7 +190,10 @@ extension WorkspaceDocument.SearchState {
183190
guard let data = try? Data(contentsOf: searchResult.file.url) else {
184191
return
185192
}
186-
let fileContent = String(decoding: data, as: UTF8.self)
193+
guard let fileContent = String(bytes: data, encoding: .utf8) else {
194+
await setStatus(.failed(errorMessage: "Failed to decode file content."))
195+
return
196+
}
187197

188198
// Attempt to create a regular expression from the provided query
189199
guard let regex = try? NSRegularExpression(
@@ -343,4 +353,29 @@ extension WorkspaceDocument.SearchState {
343353
self.findNavigatorStatus = .none
344354
}
345355
}
356+
357+
/// Evaluates a matched file to determine if it contains any search matches.
358+
/// Requires a file score from the search model.
359+
///
360+
/// Evaluates the file's contents asynchronously.
361+
///
362+
/// - Parameters:
363+
/// - fileURL: The `URL` of the file to evaluate.
364+
/// - fileScore: The file's score from a ``SearchIndexer``
365+
/// - regexPattern: The pattern to evaluate against the file's contents.
366+
/// - Returns: `nil` if there are no relevant search matches, or a search result if matches are found.
367+
private func evaluateSearchResult(
368+
fileURL: URL,
369+
fileScore: Float,
370+
regexPattern: String
371+
) async -> SearchResultModel? {
372+
var newResult = SearchResultModel(
373+
file: CEWorkspaceFile(url: fileURL),
374+
score: fileScore
375+
)
376+
377+
await evaluateFile(query: regexPattern, searchResult: &newResult)
378+
379+
return newResult.lineMatches.isEmpty ? nil : newResult
380+
}
346381
}

CodeEdit/Features/Editor/TabBar/Tabs/Tab/EditorTabCloseButton.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,10 @@ struct EditorTabCloseButton: View {
105105
}
106106
}
107107

108+
@available(macOS 14.0, *)
108109
#Preview {
109-
@State var closeButtonGestureActive: Bool = false
110-
@State var isHoveringClose: Bool = false
110+
@Previewable @State var closeButtonGestureActive: Bool = false
111+
@Previewable @State var isHoveringClose: Bool = false
111112

112113
return EditorTabCloseButton(
113114
isActive: false,

CodeEdit/Features/Editor/TabBar/Tabs/Tab/EditorTabView.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,6 @@ struct EditorTabView: View {
226226
}
227227
}
228228
)
229-
// This padding is to avoid background color overlapping with top divider.
230-
.padding(.top, 1)
231229
.zIndex(isActive ? 2 : (isDragging ? 3 : (isPressing ? 1 : 0)))
232230
.id(item.id)
233231
.tabBarContextMenu(item: item, isTemporary: isTemporary)

0 commit comments

Comments
 (0)