Skip to content

Commit 5beec87

Browse files
committed
Merge branch 'feature/prompt-to-code-with-github-copilot' into develop
2 parents 7d8609f + 23da2d4 commit 5beec87

10 files changed

Lines changed: 199 additions & 174 deletions

File tree

Copilot for Xcode/SettingsView.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ struct SettingsView: View {
2222
var disableSuggestionFeatureGlobally: Bool
2323
@AppStorage(\.suggestionFeatureEnabledProjectList)
2424
var suggestionFeatureEnabledProjectList: [String]
25+
@AppStorage(\.promptToCodeFeatureProvider)
26+
var promptToCodeFeatureProvider: PromptToCodeFeatureProvider
2527
init() {}
2628
}
2729

@@ -134,6 +136,19 @@ struct SettingsView: View {
134136
Text("Use accessibility API to accept suggestion in widget")
135137
}
136138
.toggleStyle(.switch)
139+
140+
Picker(selection: $settings.promptToCodeFeatureProvider) {
141+
ForEach(PromptToCodeFeatureProvider.allCases, id: \.rawValue) {
142+
switch $0 {
143+
case .openAI:
144+
Text("OpenAI").tag($0)
145+
case .githubCopilot:
146+
Text("GitHub Copilot (Less Accurate)").tag($0)
147+
}
148+
}
149+
} label: {
150+
Text("Prompt to code with")
151+
}
137152
}
138153
}.buttonStyle(.copilot)
139154
}

Core/Sources/Preferences/Keys.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,15 @@ public struct UserDefaultPreferenceKeys {
151151
public var suggestionFeatureEnabledProjectList: SuggestionFeatureEnabledProjectList {
152152
.init()
153153
}
154+
155+
public struct PromptToCodeFeatureProviderKey: UserDefaultPreferenceKey {
156+
public let defaultValue: PromptToCodeFeatureProvider = .openAI
157+
public let key = "PromptToCodeFeatureProvider"
158+
}
159+
160+
public var promptToCodeFeatureProvider: PromptToCodeFeatureProviderKey {
161+
.init()
162+
}
154163

155164
public var disableLazyVStack: FeatureFlags.DisableLazyVStack { .init() }
156165
public var preCacheOnFileOpen: FeatureFlags.PreCacheOnFileOpen { .init() }
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import Foundation
2+
3+
public enum PromptToCodeFeatureProvider: Int, CaseIterable {
4+
case openAI
5+
case githubCopilot
6+
}

Core/Sources/PromptToCodeService/CopilotPromptToCodeAPI.swift

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,85 @@ import Foundation
44
import OpenAIService
55

66
final class CopilotPromptToCodeAPI: PromptToCodeAPI {
7+
var task: Task<Void, Never>?
8+
79
func stopResponding() {
8-
fatalError()
10+
task?.cancel()
911
}
1012

1113
func modifyCode(
1214
code: String,
1315
language: CopilotLanguage,
1416
indentSize: Int,
1517
usesTabsForIndentation: Bool,
16-
requirement: String
18+
requirement: String,
19+
projectRootURL: URL,
20+
fileURL: URL,
21+
allCode: String
1722
) async throws -> AsyncThrowingStream<(code: String, description: String), Error> {
18-
fatalError()
23+
let copilotService = CopilotSuggestionService(projectRootURL: projectRootURL)
24+
let relativePath = {
25+
let filePath = fileURL.path
26+
let rootPath = projectRootURL.path
27+
if let range = filePath.range(of: rootPath),
28+
range.lowerBound == filePath.startIndex
29+
{
30+
let relativePath = filePath.replacingCharacters(
31+
in: filePath.startIndex..<range.upperBound,
32+
with: ""
33+
)
34+
return relativePath
35+
}
36+
return filePath
37+
}()
38+
39+
let comment = """
40+
// update the following code, \(requirement.split(separator: "\n").joined(separator: " ")).
41+
\(code.split(separator: "\n").map { "//\($0)" }.joined(separator: "\n"))
42+
43+
44+
45+
// Path: \(relativePath)
46+
47+
"""
48+
let lineCount = comment.breakLines().count
49+
50+
return .init { continuation in
51+
self.task = Task {
52+
do {
53+
let result = try await copilotService.getCompletions(
54+
fileURL: fileURL,
55+
content: comment,
56+
cursorPosition: .init(line: lineCount - 4, character: 0),
57+
tabSize: indentSize,
58+
indentSize: indentSize,
59+
usesTabsForIndentation: usesTabsForIndentation,
60+
ignoreSpaceOnlySuggestions: true
61+
)
62+
try Task.checkCancellation()
63+
guard let first = result.first else { throw CancellationError() }
64+
continuation.yield((first.text, ""))
65+
continuation.finish()
66+
} catch {
67+
continuation.finish(throwing: error)
68+
}
69+
}
70+
}
71+
}
72+
}
73+
74+
extension String {
75+
/// Break a string into lines.
76+
func breakLines() -> [String] {
77+
let lines = split(separator: "\n", omittingEmptySubsequences: false)
78+
var all = [String]()
79+
for (index, line) in lines.enumerated() {
80+
if index == lines.endIndex - 1 {
81+
all.append(String(line))
82+
} else {
83+
all.append(String(line) + "\n")
84+
}
85+
}
86+
return all
1987
}
2088
}

Core/Sources/PromptToCodeService/OpenAIPromptToCodeAPI.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ final class OpenAIPromptToCodeAPI: PromptToCodeAPI {
1717
language: CopilotLanguage,
1818
indentSize: Int,
1919
usesTabsForIndentation: Bool,
20-
requirement: String
20+
requirement: String,
21+
projectRootURL: URL,
22+
fileURL: URL,
23+
allCode: String
2124
) async throws -> AsyncThrowingStream<(code: String, description: String), Error> {
2225
let userPreferredLanguage = UserDefaults.shared.value(for: \.chatGPTLanguage)
2326
let textLanguage = userPreferredLanguage.isEmpty ? "" : "in \(userPreferredLanguage)"

0 commit comments

Comments
 (0)