Skip to content

Commit f9f19c1

Browse files
committed
Update prompt to code to be able to accept multiple modifications
1 parent 7e8338d commit f9f19c1

File tree

3 files changed

+82
-70
lines changed

3 files changed

+82
-70
lines changed

Core/Sources/Service/SuggestionCommandHandler/PseudoCommandHandler.swift

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -209,18 +209,23 @@ struct PseudoCommandHandler: CommandHandler {
209209
try await XcodeInspector.shared.safe.latestActiveXcode?
210210
.triggerCopilotCommand(name: "Accept Modification")
211211
} catch {
212-
let last = Self.lastTimeCommandFailedToTriggerWithAccessibilityAPI
213-
let now = Date()
214-
if now.timeIntervalSince(last) > 60 * 60 {
215-
Self.lastTimeCommandFailedToTriggerWithAccessibilityAPI = now
216-
toast.toast(content: """
212+
do {
213+
try await XcodeInspector.shared.safe.latestActiveXcode?
214+
.triggerCopilotCommand(name: "Accept Prompt to Code")
215+
} catch {
216+
let last = Self.lastTimeCommandFailedToTriggerWithAccessibilityAPI
217+
let now = Date()
218+
if now.timeIntervalSince(last) > 60 * 60 {
219+
Self.lastTimeCommandFailedToTriggerWithAccessibilityAPI = now
220+
toast.toast(content: """
217221
The app is using a fallback solution to accept suggestions. \
218222
For better experience, please restart Xcode to re-activate the Copilot \
219223
menu item.
220224
""", type: .warning)
225+
}
226+
227+
throw error
221228
}
222-
223-
throw error
224229
}
225230
} catch {
226231
guard let xcode = ActiveApplicationMonitor.shared.activeXcode

Core/Sources/Service/SuggestionCommandHandler/WindowBaseCommandHandler.swift

Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -177,59 +177,58 @@ struct WindowBaseCommandHandler: SuggestionCommandHandler {
177177

178178
let injector = SuggestionInjector()
179179
var lines = editor.lines
180-
var ranges = [CursorRange]()
181180
var cursorPosition = editor.cursorPosition
182181
var extraInfo = SuggestionInjector.ExtraInfo()
183182

184183
let store = await Service.shared.guiController.store
185184

186-
if let promptToCode = store.state.promptToCodeGroup.activePromptToCode {
185+
if let promptToCode = await MainActor
186+
.run(body: { store.state.promptToCodeGroup.activePromptToCode })
187+
{
187188
if promptToCode.promptToCodeState.isAttachedToTarget,
188189
promptToCode.promptToCodeState.source.documentURL != fileURL
189190
{
190191
return nil
191192
}
192193

193-
for snippet in promptToCode.promptToCodeState.snippets.sorted(by: { a, b in
194-
a.attachedRange.start.line > b.attachedRange.start.line
195-
}) {
196-
let range = {
197-
if promptToCode.promptToCodeState.isAttachedToTarget {
198-
return snippet.attachedRange
199-
}
200-
return editor.selections.first.map {
201-
CursorRange(start: $0.start, end: $0.end)
202-
} ?? CursorRange(
203-
start: editor.cursorPosition,
204-
end: editor.cursorPosition
194+
let suggestions = promptToCode.promptToCodeState.snippets
195+
.map { snippet in
196+
let range = {
197+
if promptToCode.promptToCodeState.isAttachedToTarget {
198+
return snippet.attachedRange
199+
}
200+
return editor.selections.first.map {
201+
CursorRange(start: $0.start, end: $0.end)
202+
} ?? CursorRange(
203+
start: editor.cursorPosition,
204+
end: editor.cursorPosition
205+
)
206+
}()
207+
return CodeSuggestion(
208+
id: snippet.id.uuidString,
209+
text: snippet.modifiedCode,
210+
position: range.start,
211+
range: range
205212
)
206-
}()
207-
208-
ranges.append(range)
209-
210-
let suggestion = CodeSuggestion(
211-
id: UUID().uuidString,
212-
text: snippet.modifiedCode,
213-
position: range.start,
214-
range: range
215-
)
213+
}
216214

217-
injector.acceptSuggestion(
218-
intoContentWithoutSuggestion: &lines,
219-
cursorPosition: &cursorPosition,
220-
completion: suggestion,
221-
extraInfo: &extraInfo
222-
)
215+
injector.acceptSuggestions(
216+
intoContentWithoutSuggestion: &lines,
217+
cursorPosition: &cursorPosition,
218+
completions: suggestions,
219+
extraInfo: &extraInfo
220+
)
223221

224-
_ = await Task { @MainActor [cursorPosition] in
225-
await store.send(
222+
for (id, range) in extraInfo.modificationRanges {
223+
_ = await MainActor.run {
224+
store.send(
226225
.promptToCodeGroup(.updatePromptToCodeRange(
227226
id: promptToCode.id,
228-
snippetId: snippet.id,
229-
range: .init(start: range.start, end: cursorPosition)
227+
snippetId: .init(uuidString: id) ?? .init(),
228+
range: range
230229
))
231-
).finish()
232-
}.value
230+
)
231+
}
233232
}
234233

235234
_ = await MainActor.run {
@@ -242,7 +241,8 @@ struct WindowBaseCommandHandler: SuggestionCommandHandler {
242241

243242
return .init(
244243
content: String(lines.joined(separator: "")),
245-
newSelections: ranges,
244+
newSelections: extraInfo.modificationRanges.values
245+
.sorted(by: { $0.start.line <= $1.start.line }),
246246
modifications: extraInfo.modifications
247247
)
248248
}
@@ -436,10 +436,10 @@ extension WindowBaseCommandHandler {
436436
content: editor.content,
437437
lines: editor.lines
438438
),
439-
snippets: IdentifiedArray(snippets),
439+
snippets: IdentifiedArray(uniqueElements: snippets),
440440
instruction: newPrompt ?? "",
441441
extraSystemPrompt: newExtraSystemPrompt ?? "",
442-
isAttachedToTarget: false
442+
isAttachedToTarget: true
443443
)),
444444
indentSize: filespace.codeMetadata.indentSize ?? 4,
445445
usesTabsForIndentation: filespace.codeMetadata.usesTabsForIndentation ?? false,

Core/Sources/SuggestionWidget/SuggestionPanelContent/PromptToCodePanelView.swift

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -191,11 +191,13 @@ extension PromptToCodePanelView {
191191
if !isResponding || isRespondingButCodeIsReady {
192192
HStack {
193193
Menu {
194-
Toggle(
195-
"Always accept and continue",
196-
isOn: $store.isContinuous.animation(.easeInOut(duration: 0.1))
197-
)
198-
.toggleStyle(.checkbox)
194+
WithPerceptionTracking {
195+
Toggle(
196+
"Always accept and continue",
197+
isOn: $store.isContinuous.animation(.easeInOut(duration: 0.1))
198+
)
199+
.toggleStyle(.checkbox)
200+
}
199201
} label: {
200202
Image(systemName: "gearshape.fill")
201203
.foregroundStyle(.secondary)
@@ -314,27 +316,32 @@ extension PromptToCodePanelView {
314316
var body: some View {
315317
WithPerceptionTracking {
316318
ScrollView {
317-
VStack(spacing: 0) {
318-
Spacer(minLength: 56)
319-
319+
WithPerceptionTracking {
320320
VStack(spacing: 0) {
321-
let language = store.promptToCodeState.source.language
322-
let isAttached = store.promptToCodeState.isAttachedToTarget
323-
ForEach(store.scope(
324-
state: \.snippetPanels,
325-
action: \.snippetPanel
326-
)) { snippetStore in
327-
if snippetStore.id != store.promptToCodeState.snippets.last?.id {
328-
Divider()
321+
Spacer(minLength: 56)
322+
323+
VStack(spacing: 0) {
324+
let language = store.promptToCodeState.source.language
325+
let isAttached = store.promptToCodeState.isAttachedToTarget
326+
let lastId = store.promptToCodeState.snippets.last?.id
327+
ForEach(store.scope(
328+
state: \.snippetPanels,
329+
action: \.snippetPanel
330+
)) { snippetStore in
331+
WithPerceptionTracking {
332+
if snippetStore.id != lastId {
333+
Divider()
334+
}
335+
336+
SnippetPanelView(
337+
store: snippetStore,
338+
language: language,
339+
codeForegroundColor: codeForegroundColor ?? .primary,
340+
codeBackgroundColor: codeBackgroundColor,
341+
isAttached: isAttached
342+
)
343+
}
329344
}
330-
331-
SnippetPanelView(
332-
store: snippetStore,
333-
language: language,
334-
codeForegroundColor: codeForegroundColor ?? .primary,
335-
codeBackgroundColor: codeBackgroundColor,
336-
isAttached: isAttached
337-
)
338345
}
339346
}
340347
}

0 commit comments

Comments
 (0)