Skip to content

Commit 08dc9f6

Browse files
committed
Performance improvements
1 parent 9885978 commit 08dc9f6

File tree

3 files changed

+122
-35
lines changed

3 files changed

+122
-35
lines changed

CodeEdit/Features/Activities/ActivityManager.swift

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ final class ActivityManager: ObservableObject {
1515
/// Currently displayed activities
1616
@Published private(set) var activities: [CEActivity] = []
1717

18+
/// Debounce work item for batching updates
19+
private var updateWorkItems: [String: DispatchWorkItem] = [:]
20+
1821
/// Posts a new activity
1922
/// - Parameters:
2023
/// - priority: Whether to insert at start of list
@@ -50,7 +53,7 @@ final class ActivityManager: ObservableObject {
5053
return activity
5154
}
5255

53-
/// Updates an existing activity
56+
/// Updates an existing activity with debouncing
5457
/// - Parameters:
5558
/// - id: ID of activity to update
5659
/// - title: New title (optional)
@@ -64,29 +67,49 @@ final class ActivityManager: ObservableObject {
6467
percentage: Double? = nil,
6568
isLoading: Bool? = nil
6669
) {
67-
if let index = activities.firstIndex(where: { $0.id == id }) {
68-
var activity = activities[index]
70+
// Cancel any pending update for this specific activity
71+
updateWorkItems[id]?.cancel()
6972

70-
if let title = title {
71-
activity.title = title
72-
}
73-
if let message = message {
74-
activity.message = message
75-
}
76-
if let percentage = percentage {
77-
activity.percentage = percentage
78-
}
79-
if let isLoading = isLoading {
80-
activity.isLoading = isLoading
73+
// Create new work item
74+
let workItem = DispatchWorkItem { [weak self] in
75+
guard let self else { return }
76+
77+
if let index = self.activities.firstIndex(where: { $0.id == id }) {
78+
var activity = self.activities[index]
79+
80+
if let title = title {
81+
activity.title = title
82+
}
83+
if let message = message {
84+
activity.message = message
85+
}
86+
if let percentage = percentage {
87+
activity.percentage = percentage
88+
}
89+
if let isLoading = isLoading {
90+
activity.isLoading = isLoading
91+
}
92+
93+
withAnimation(.easeInOut(duration: 0.15)) {
94+
self.activities[index] = activity
95+
}
8196
}
8297

83-
activities[index] = activity
98+
self.updateWorkItems.removeValue(forKey: id)
8499
}
100+
101+
// Store work item and schedule after delay
102+
updateWorkItems[id] = workItem
103+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.05, execute: workItem)
85104
}
86105

87106
/// Deletes an activity
88107
/// - Parameter id: ID of activity to delete
89108
func delete(id: String) {
109+
// Clear any pending updates for this activity
110+
updateWorkItems[id]?.cancel()
111+
updateWorkItems.removeValue(forKey: id)
112+
90113
withAnimation(.easeInOut(duration: 0.3)) {
91114
activities.removeAll { $0.id == id }
92115
}

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

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,42 +27,53 @@ extension WorkspaceDocument.SearchState {
2727

2828
Task.detached {
2929
let filePaths = self.getFileURLs(at: url)
30-
3130
let asyncController = SearchIndexer.AsyncManager(index: indexer)
3231
var lastProgress: Double = 0
3332

33+
// Batch our progress updates
34+
var pendingProgress: Double?
35+
36+
func updateProgress(_ progress: Double) async {
37+
await MainActor.run {
38+
self.indexStatus = .indexing(progress: progress)
39+
self.workspace.activityManager.update(
40+
id: activity.id,
41+
percentage: progress
42+
)
43+
}
44+
}
45+
3446
for await (file, index) in AsyncFileIterator(fileURLs: filePaths) {
3547
_ = await asyncController.addText(files: [file], flushWhenComplete: false)
3648
let progress = Double(index) / Double(filePaths.count)
3749

38-
// Send only if difference is > 0.5%, to keep updates from sending too frequently
39-
if progress - lastProgress > 0.005 || index == filePaths.count - 1 {
50+
// Send only if difference is > 1%
51+
if progress - lastProgress > 0.01 {
4052
lastProgress = progress
41-
await MainActor.run {
42-
self.indexStatus = .indexing(progress: progress)
53+
pendingProgress = progress
54+
55+
// Only update UI every 100ms
56+
if index == filePaths.count - 1 || pendingProgress != nil {
57+
await updateProgress(progress)
58+
pendingProgress = nil
4359
}
44-
await self.workspace.activityManager.update(
45-
id: activity.id,
46-
percentage: progress
47-
)
4860
}
4961
}
62+
5063
asyncController.index.flush()
5164

5265
await MainActor.run {
5366
self.indexStatus = .done
67+
self.workspace.activityManager.update(
68+
id: activity.id,
69+
title: "Finished indexing",
70+
isLoading: false
71+
)
72+
self.workspace.activityManager.delete(
73+
id: activity.id,
74+
delay: 4.0
75+
)
5476
}
55-
56-
await self.workspace.activityManager.update(
57-
id: activity.id,
58-
title: "Finished indexing",
59-
isLoading: false
60-
)
61-
62-
await self.workspace.activityManager.delete(
63-
id: activity.id,
64-
delay: 4.0
65-
)
6677
}
6778
}
6879

CodeEdit/Features/InspectorArea/InternalDevelopmentInspector/InternalDevelopmentActivitiesView.swift

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ struct InternalDevelopmentActivitiesView: View {
1818
@State private var autoDelete: Bool = false
1919
@State private var deleteDelay: Double = 3.0
2020

21+
// New state for progress timer
22+
@State private var isProgressTimerRunning: Bool = false
23+
@State private var progressActivity: CEActivity?
24+
2125
var body: some View {
2226
Section("Activities") {
2327
Toggle("Priority", isOn: $isPriority)
@@ -70,6 +74,55 @@ struct InternalDevelopmentActivitiesView: View {
7074
}
7175
}
7276
}
77+
78+
Section("Progress Timer Test") {
79+
Button(isProgressTimerRunning ? "Stop Progress Timer" : "Start Progress Timer") {
80+
if isProgressTimerRunning {
81+
isProgressTimerRunning = false
82+
if let activity = progressActivity {
83+
activityManager.delete(id: activity.id)
84+
}
85+
progressActivity = nil
86+
} else {
87+
isProgressTimerRunning = true
88+
progressActivity = activityManager.post(
89+
priority: isPriority,
90+
title: "Progress Timer",
91+
message: "Updating every 50ms",
92+
percentage: 0.0
93+
)
94+
95+
// Start timer to update progress
96+
Task { @MainActor in
97+
var progress = 0.0
98+
while isProgressTimerRunning && progress < 1.0 {
99+
// Update in 5% increments
100+
progress = min(1.0, progress + 0.05)
101+
if let activity = progressActivity {
102+
activityManager.update(
103+
id: activity.id,
104+
percentage: progress
105+
)
106+
}
107+
// Wait longer between updates
108+
try? await Task.sleep(for: .milliseconds(100))
109+
}
110+
111+
// Cleanup when done
112+
if let activity = progressActivity {
113+
activityManager.update(
114+
id: activity.id,
115+
title: "Progress Timer Complete",
116+
percentage: 1.0
117+
)
118+
activityManager.delete(id: activity.id, delay: 2.0)
119+
}
120+
isProgressTimerRunning = false
121+
progressActivity = nil
122+
}
123+
}
124+
}
125+
}
73126
}
74127
}
75128
}

0 commit comments

Comments
 (0)