Skip to content

Commit 8d58436

Browse files
committed
Dsiplay status in modification
1 parent 78d22b8 commit 8d58436

4 files changed

Lines changed: 148 additions & 12 deletions

File tree

Core/Sources/SuggestionWidget/FeatureReducers/PromptToCodePanel.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ public struct PromptToCodePanel {
8484
case cancelButtonTapped
8585
case acceptButtonTapped
8686
case acceptAndContinueButtonTapped
87+
case statusUpdated([String])
8788
case snippetPanel(IdentifiedActionOf<PromptToCodeSnippetPanel>)
8889
}
8990

@@ -128,7 +129,9 @@ public struct PromptToCodePanel {
128129

129130
return .run { send in
130131
do {
131-
let context = await contextInputController.resolveContext()
132+
let context = await contextInputController.resolveContext(onStatusChange: {
133+
await send(.statusUpdated($0))
134+
})
132135
let agentFactory = context.agent ?? { SimpleModificationAgent() }
133136
_ = try await withThrowingTaskGroup(of: Void.self) { group in
134137
for (index, snippet) in snippets.enumerated() {
@@ -216,11 +219,13 @@ public struct PromptToCodePanel {
216219

217220
case .stopRespondingButtonTapped:
218221
state.promptToCodeState.isGenerating = false
222+
state.promptToCodeState.status = []
219223
return .cancel(id: CancellationKey.modifyCode(state.id))
220224

221225
case .modifyCodeFinished:
222226
state.contextInputController.instruction = .init("")
223227
state.promptToCodeState.isGenerating = false
228+
state.promptToCodeState.status = []
224229

225230
if state.promptToCodeState.snippets.allSatisfy({ snippet in
226231
snippet.modifiedCode.isEmpty && snippet.description.isEmpty && snippet
@@ -252,6 +257,10 @@ public struct PromptToCodePanel {
252257
await commandHandler.acceptModification()
253258
activateThisApp()
254259
}
260+
261+
case let .statusUpdated(status):
262+
state.promptToCodeState.status = status
263+
return .none
255264
}
256265
}
257266

Core/Sources/SuggestionWidget/SuggestionPanelContent/PromptToCodePanelView.swift

Lines changed: 130 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,17 @@ struct PromptToCodePanelView: View {
2323
TopBar(store: store)
2424

2525
Content(store: store)
26-
.overlay(alignment: .bottom) {
27-
ActionBar(store: store)
28-
}
2926
.safeAreaInset(edge: .bottom) {
30-
if let inputField = customizedViews.contextInputField {
31-
inputField
32-
} else {
33-
Toolbar(store: store)
27+
VStack {
28+
StatusBar(store: store)
29+
30+
ActionBar(store: store)
31+
32+
if let inputField = customizedViews.contextInputField {
33+
inputField
34+
} else {
35+
Toolbar(store: store)
36+
}
3437
}
3538
}
3639
}
@@ -143,6 +146,70 @@ extension PromptToCodePanelView {
143146
}
144147
}
145148

149+
struct StatusBar: View {
150+
let store: StoreOf<PromptToCodePanel>
151+
@State var isAllStatusesPresented = false
152+
var body: some View {
153+
WithPerceptionTracking {
154+
if store.promptToCodeState.isGenerating, !store.promptToCodeState.status.isEmpty {
155+
if let firstStatus = store.promptToCodeState.status.first {
156+
let count = store.promptToCodeState.status.count
157+
Button(action: {
158+
isAllStatusesPresented = true
159+
}) {
160+
HStack {
161+
Text(firstStatus)
162+
.lineLimit(1)
163+
.font(.caption)
164+
165+
Text("\(count)")
166+
.lineLimit(1)
167+
.font(.caption)
168+
.background(
169+
Circle()
170+
.fill(Color.secondary.opacity(0.3))
171+
.frame(width: 12, height: 12)
172+
)
173+
}
174+
.padding(8)
175+
.background(
176+
.regularMaterial,
177+
in: RoundedRectangle(cornerRadius: 6, style: .continuous)
178+
)
179+
.overlay {
180+
RoundedRectangle(cornerRadius: 6, style: .continuous)
181+
.stroke(Color(nsColor: .separatorColor), lineWidth: 1)
182+
}
183+
.contentShape(Rectangle())
184+
}
185+
.buttonStyle(.plain)
186+
.frame(maxWidth: 400)
187+
.popover(isPresented: $isAllStatusesPresented, arrowEdge: .top) {
188+
WithPerceptionTracking {
189+
VStack(alignment: .leading, spacing: 16) {
190+
ForEach(store.promptToCodeState.status, id: \.self) { status in
191+
HStack {
192+
ProgressView()
193+
.progressViewStyle(CircularProgressViewStyle())
194+
.controlSize(.small)
195+
Text(status)
196+
}
197+
}
198+
}
199+
.padding()
200+
}
201+
}
202+
.onChange(of: store.promptToCodeState.isGenerating) { isGenerating in
203+
if !isGenerating {
204+
isAllStatusesPresented = false
205+
}
206+
}
207+
}
208+
}
209+
}
210+
}
211+
}
212+
146213
struct ActionBar: View {
147214
let store: StoreOf<PromptToCodePanel>
148215

@@ -888,3 +955,59 @@ extension PromptToCodePanelView {
888955
.frame(width: 500, height: 500, alignment: .center)
889956
}
890957

958+
#Preview("Geenrating") {
959+
PromptToCodePanelView(store: .init(initialState: .init(
960+
promptToCodeState: Shared(ModificationState(
961+
source: .init(
962+
language: CodeLanguage.builtIn(.swift),
963+
documentURL: URL(
964+
fileURLWithPath: "path/to/file-name-is-super-long-what-should-we-do-with-it-hah.txt"
965+
),
966+
projectRootURL: URL(fileURLWithPath: "path/to/file.txt"),
967+
content: "",
968+
lines: []
969+
),
970+
snippets: [
971+
.init(
972+
startLineIndex: 8,
973+
originalCode: "print(foo)",
974+
modifiedCode: "print(bar)",
975+
description: "",
976+
error: "Error",
977+
attachedRange: CursorRange(
978+
start: .init(line: 8, character: 0),
979+
end: .init(line: 12, character: 2)
980+
)
981+
),
982+
.init(
983+
startLineIndex: 13,
984+
originalCode: """
985+
struct Bar {
986+
var foo: Int
987+
}
988+
""",
989+
modifiedCode: """
990+
struct Bar {
991+
var foo: String
992+
}
993+
""",
994+
description: "Cool",
995+
error: nil,
996+
attachedRange: CursorRange(
997+
start: .init(line: 13, character: 0),
998+
end: .init(line: 12, character: 2)
999+
)
1000+
),
1001+
],
1002+
extraSystemPrompt: "",
1003+
isAttachedToTarget: true,
1004+
isGenerating: true,
1005+
status: ["Status 1", "Status 2"]
1006+
)),
1007+
instruction: nil,
1008+
commandName: "Generate Code"
1009+
), reducer: { PromptToCodePanel() }))
1010+
.frame(maxWidth: 450, maxHeight: Style.panelHeight)
1011+
.fixedSize(horizontal: false, vertical: true)
1012+
.frame(width: 500, height: 500, alignment: .center)
1013+
}

Tool/Sources/ModificationBasic/ModificationState.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,24 @@ public struct ModificationState {
1111
public var isGenerating: Bool = false
1212
public var extraSystemPrompt: String
1313
public var isAttachedToTarget: Bool = true
14+
public var status = [String]()
1415

1516
public init(
1617
source: Source,
1718
history: [ModificationHistoryNode] = [],
1819
snippets: IdentifiedArrayOf<ModificationSnippet>,
1920
extraSystemPrompt: String,
20-
isAttachedToTarget: Bool
21+
isAttachedToTarget: Bool,
22+
isGenerating: Bool = false,
23+
status: [String] = []
2124
) {
2225
self.history = history
2326
self.snippets = snippets
24-
isGenerating = false
27+
self.isGenerating = isGenerating
2528
self.isAttachedToTarget = isAttachedToTarget
2629
self.extraSystemPrompt = extraSystemPrompt
2730
self.source = source
31+
self.status = status
2832
}
2933

3034
public init(

Tool/Sources/PromptToCodeCustomization/PromptToCodeCustomization.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public protocol PromptToCodeContextInputControllerDelegate {
5555
public protocol PromptToCodeContextInputController: Perception.Perceptible {
5656
var instruction: NSAttributedString { get set }
5757

58-
func resolveContext() async -> (
58+
func resolveContext(onStatusChange: @escaping ([String]) async -> Void) async -> (
5959
instruction: String,
6060
references: [ChatMessage.Reference],
6161
topics: [ChatMessage.Reference],
@@ -100,7 +100,7 @@ public final class DefaultPromptToCodeContextInputController: PromptToCodeContex
100100
instruction = mutable
101101
}
102102

103-
public func resolveContext() -> (
103+
public func resolveContext(onStatusChange: @escaping ([String]) async -> Void) -> (
104104
instruction: String,
105105
references: [ChatMessage.Reference],
106106
topics: [ChatMessage.Reference],

0 commit comments

Comments
 (0)