Skip to content

Commit 162d52b

Browse files
committed
Fix
1 parent 5bfe0a6 commit 162d52b

3 files changed

Lines changed: 73 additions & 37 deletions

File tree

Core/Sources/SuggestionWidget/FeatureReducers/PromptToCodePanel.swift

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -173,41 +173,48 @@ public struct PromptToCodePanel {
173173
range: snippet.attachedRange,
174174
references: context.references,
175175
topics: context.topics
176-
)).timedDebounce(for: 0.4)
176+
)).map {
177+
switch $0 {
178+
case let .code(code):
179+
return (code: code, description: "")
180+
case let .explanation(explanation):
181+
return (code: "", description: explanation)
182+
}
183+
}.timedDebounce(for: 0.4) { lhs, rhs in
184+
(
185+
code: lhs.code + rhs.code,
186+
description: lhs.description + rhs.description
187+
)
188+
}
177189

178190
do {
179191
for try await response in stream {
180192
try Task.checkCancellation()
181-
182-
switch response {
183-
case let .code(code):
184-
await send(.snippetPanel(.element(
185-
id: snippet.id,
186-
action: .modifyCodeChunkReceived(
187-
code: code,
188-
description: ""
189-
)
190-
)))
191-
case let .explanation(explanation):
192-
await send(.snippetPanel(.element(
193-
id: snippet.id,
194-
action: .modifyCodeChunkReceived(
195-
code: "",
196-
description: explanation
197-
)
198-
)))
199-
}
193+
await send(.snippetPanel(.element(
194+
id: snippet.id,
195+
action: .modifyCodeChunkReceived(
196+
code: response.code,
197+
description: response.description
198+
)
199+
)))
200200
}
201+
await send(.snippetPanel(.element(
202+
id: snippet.id,
203+
action: .modifyCodeFinished
204+
)))
201205
} catch is CancellationError {
206+
await send(.snippetPanel(.element(
207+
id: snippet.id,
208+
action: .modifyCodeFinished
209+
)))
202210
throw CancellationError()
203211
} catch {
204-
try Task.checkCancellation()
205212
if (error as NSError).code == NSURLErrorCancelled {
206213
await send(.snippetPanel(.element(
207214
id: snippet.id,
208-
action: .modifyCodeFailed(error: "Cancelled")
215+
action: .modifyCodeFinished
209216
)))
210-
return
217+
throw CancellationError()
211218
}
212219
await send(.snippetPanel(.element(
213220
id: snippet.id,

Core/Sources/SuggestionWidget/SuggestionPanelContent/PromptToCodePanelView.swift

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -288,12 +288,8 @@ extension PromptToCodePanelView {
288288
let isResponding = store.promptToCodeState.isGenerating
289289
let isCodeEmpty = store.promptToCodeState.snippets
290290
.allSatisfy(\.modifiedCode.isEmpty)
291-
let isDescriptionEmpty = store.promptToCodeState.snippets
292-
.allSatisfy(\.description.isEmpty)
293291
var isRespondingButCodeIsReady: Bool {
294-
isResponding
295-
&& !isCodeEmpty
296-
&& !isDescriptionEmpty
292+
isResponding && !isCodeEmpty
297293
}
298294
if !isResponding || isRespondingButCodeIsReady {
299295
HStack {
@@ -619,20 +615,23 @@ extension PromptToCodePanelView {
619615

620616
var body: some View {
621617
WithPerceptionTracking {
622-
VStack(spacing: 0) {
618+
VStack(alignment: .leading, spacing: 0) {
623619
SnippetTitleBar(
624620
store: store,
625621
language: language,
626622
codeForegroundColor: codeForegroundColor,
627623
isAttached: isAttached
628624
)
625+
626+
DescriptionContent(store: store, codeForegroundColor: codeForegroundColor)
627+
629628
CodeContent(
630629
store: store,
631630
language: language,
632631
isGenerating: isGenerating,
633632
codeForegroundColor: codeForegroundColor
634633
)
635-
DescriptionContent(store: store, codeForegroundColor: codeForegroundColor)
634+
636635
ErrorMessage(store: store)
637636
}
638637
}
@@ -1146,7 +1145,12 @@ extension PromptToCodePanelView {
11461145
ChatMessage.Reference(
11471146
title: "Foo",
11481147
content: "struct Foo { var foo: Int }",
1149-
kind: .symbol(.struct, uri: "file:///path/to/file.txt", startLine: 13, endLine: 13)
1148+
kind: .symbol(
1149+
.struct,
1150+
uri: "file:///path/to/file.txt",
1151+
startLine: 13,
1152+
endLine: 13
1153+
)
11501154
),
11511155
],
11521156
)),

Tool/Sources/CustomAsyncAlgorithms/TimedDebounce.swift

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,18 +46,27 @@ public extension AsyncSequence {
4646
///
4747
/// In the future when we drop macOS 12 support we should just use chunked from AsyncAlgorithms.
4848
func timedDebounce(
49-
for duration: TimeInterval
49+
for duration: TimeInterval,
50+
reducer: @escaping @Sendable (Element, Element) -> Element
5051
) -> AsyncThrowingStream<Element, Error> {
5152
return AsyncThrowingStream { continuation in
5253
Task {
53-
let function = TimedDebounceFunction(duration: duration) { value in
54-
continuation.yield(value)
55-
}
54+
let storage = TimedDebounceStorage<Element>()
55+
var lastTimeStamp = Date()
5656
do {
5757
for try await value in self {
58-
await function(value)
58+
await storage.reduce(value, reducer: reducer)
59+
let now = Date()
60+
if now.timeIntervalSince(lastTimeStamp) >= duration {
61+
lastTimeStamp = now
62+
if let value = await storage.consume() {
63+
continuation.yield(value)
64+
}
65+
}
66+
}
67+
if let value = await storage.consume() {
68+
continuation.yield(value)
5969
}
60-
await function.finish()
6170
continuation.finish()
6271
} catch {
6372
continuation.finish(throwing: error)
@@ -67,3 +76,19 @@ public extension AsyncSequence {
6776
}
6877
}
6978

79+
private actor TimedDebounceStorage<Element> {
80+
var value: Element?
81+
func reduce(_ value: Element, reducer: (Element, Element) -> Element) async {
82+
if let existing = self.value {
83+
self.value = reducer(existing, value)
84+
} else {
85+
self.value = value
86+
}
87+
}
88+
89+
func consume() -> Element? {
90+
defer { value = nil }
91+
return value
92+
}
93+
}
94+

0 commit comments

Comments
 (0)