Skip to content

Commit 95abf9d

Browse files
committed
Merge branch 'feature/expain-code-with-chatgpt' into develop
2 parents f652d0a + 4d53673 commit 95abf9d

37 files changed

Lines changed: 836 additions & 93 deletions

Copilot for Xcode.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
C8C8B60929AFA35F00034BEE /* CopilotForXcodeExtensionService.app in Embed XPCService */ = {isa = PBXBuildFile; fileRef = C861E60E2994F6070056CB02 /* CopilotForXcodeExtensionService.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
4949
C8EE079D29CC21300043B6D9 /* AccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8EE079C29CC21300043B6D9 /* AccountView.swift */; };
5050
C8EE079F29CC25C20043B6D9 /* OpenAIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8EE079E29CC25C20043B6D9 /* OpenAIView.swift */; };
51+
C8EE07A129CC9ED30043B6D9 /* ExplainSelectionCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8EE07A029CC9ED30043B6D9 /* ExplainSelectionCommand.swift */; };
5152
/* End PBXBuildFile section */
5253

5354
/* Begin PBXContainerItemProxy section */
@@ -192,6 +193,7 @@
192193
C8CD828229B88006008D044D /* TestPlan.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = TestPlan.xctestplan; sourceTree = "<group>"; };
193194
C8EE079C29CC21300043B6D9 /* AccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountView.swift; sourceTree = "<group>"; };
194195
C8EE079E29CC25C20043B6D9 /* OpenAIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenAIView.swift; sourceTree = "<group>"; };
196+
C8EE07A029CC9ED30043B6D9 /* ExplainSelectionCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExplainSelectionCommand.swift; sourceTree = "<group>"; };
195197
/* End PBXFileReference section */
196198

197199
/* Begin PBXFrameworksBuildPhase section */
@@ -254,6 +256,7 @@
254256
C8009BFE2941C551007AA7E8 /* ToggleRealtimeSuggestionsCommand.swift */,
255257
C8009C022941C576007AA7E8 /* RealtimeSuggestionCommand.swift */,
256258
C800DBB0294C624D00B04CAC /* PrefetchSuggestionsCommand.swift */,
259+
C8EE07A029CC9ED30043B6D9 /* ExplainSelectionCommand.swift */,
257260
C81458972939EFDC00135263 /* Info.plist */,
258261
C81458982939EFDC00135263 /* EditorExtension.entitlements */,
259262
);
@@ -523,6 +526,7 @@
523526
C87B03A9293B262600C77EAE /* NextSuggestionCommand.swift in Sources */,
524527
C87B03AB293B262E00C77EAE /* PreviousSuggestionCommand.swift in Sources */,
525528
C87B03A7293B261900C77EAE /* RejectSuggestionCommand.swift in Sources */,
529+
C8EE07A129CC9ED30043B6D9 /* ExplainSelectionCommand.swift in Sources */,
526530
C8009C032941C576007AA7E8 /* RealtimeSuggestionCommand.swift in Sources */,
527531
C800DBB1294C624D00B04CAC /* PrefetchSuggestionsCommand.swift in Sources */,
528532
C81458962939EFDC00135263 /* GetSuggestionsCommand.swift in Sources */,

Copilot for Xcode.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Copilot for Xcode/OpenAIView.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ final class OpenAIViewSettings: ObservableObject {
88
@AppStorage(\.openAIAPIKey) var openAIAPIKey: String
99
@AppStorage(\.chatGPTModel) var chatGPTModel: String
1010
@AppStorage(\.chatGPTEndpoint) var chatGPTEndpoint: String
11+
@AppStorage(\.chatGPTLanguage) var chatGPTLanguage: String
12+
@AppStorage(\.chatGPTMaxToken) var chatGPTMaxToken: Int
1113
init() {}
1214
}
1315

@@ -63,6 +65,29 @@ struct OpenAIView: View {
6365
EmptyView()
6466
}.textFieldStyle(.copilot)
6567
}
68+
69+
HStack {
70+
Text("Reply in Language")
71+
TextField(
72+
text: $settings.chatGPTLanguage,
73+
prompt: Text("English")
74+
) {
75+
EmptyView()
76+
}.textFieldStyle(.copilot)
77+
}
78+
79+
HStack {
80+
Text("Max Token")
81+
TextField(
82+
text: .init(get: {
83+
String(settings.chatGPTMaxToken)
84+
}, set: { newValue in
85+
settings.chatGPTMaxToken = Int(newValue) ?? 0
86+
})
87+
) {
88+
EmptyView()
89+
}.textFieldStyle(.copilot)
90+
}
6691
}
6792
}
6893
}

Core/Package.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ let package = Package(
3636
.package(url: "https://github.com/raspu/Highlightr", from: "2.1.0"),
3737
.package(url: "https://github.com/JohnSundell/Splash", from: "0.1.0"),
3838
.package(url: "https://github.com/nmdias/FeedKit", from: "9.1.2"),
39+
.package(url: "https://github.com/gonzalezreal/swift-markdown-ui", from: "2.0.0"),
3940
],
4041
targets: [
4142
.target(name: "CGEventObserver"),
@@ -72,6 +73,7 @@ let package = Package(
7273
dependencies: [
7374
"CopilotModel",
7475
"CopilotService",
76+
"OpenAIService",
7577
"Preferences",
7678
"XPCShared",
7779
"CGEventObserver",
@@ -118,6 +120,7 @@ let package = Package(
118120
"Environment",
119121
"Highlightr",
120122
"Splash",
123+
.product(name: "MarkdownUI", package: "swift-markdown-ui"),
121124
]
122125
),
123126
.target(
@@ -128,7 +131,10 @@ let package = Package(
128131
.target(name: "Logger"),
129132
.target(
130133
name: "OpenAIService",
131-
dependencies: [.product(name: "AsyncAlgorithms", package: "swift-async-algorithms")]
134+
dependencies: [
135+
"Logger",
136+
.product(name: "AsyncAlgorithms", package: "swift-async-algorithms")
137+
]
132138
),
133139
.testTarget(
134140
name: "OpenAIServiceTests",

Core/Sources/ActiveApplicationMonitor/ActiveApplicationMonitor.swift

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,14 @@ import AppKit
22

33
public final class ActiveApplicationMonitor {
44
static let shared = ActiveApplicationMonitor()
5-
var activeApplication = NSWorkspace.shared.runningApplications.first(where: \.isActive)
5+
var latestXcode: NSRunningApplication?
6+
var activeApplication = NSWorkspace.shared.runningApplications.first(where: \.isActive) {
7+
didSet {
8+
if activeApplication?.isXcode ?? false {
9+
latestXcode = activeApplication
10+
}
11+
}
12+
}
613
private var continuations: [UUID: AsyncStream<NSRunningApplication?>.Continuation] = [:]
714

815
private init() {
@@ -28,11 +35,13 @@ public final class ActiveApplicationMonitor {
2835
public static var activeApplication: NSRunningApplication? { shared.activeApplication }
2936

3037
public static var activeXcode: NSRunningApplication? {
31-
if activeApplication?.bundleIdentifier == "com.apple.dt.Xcode" {
38+
if activeApplication?.isXcode ?? false {
3239
return activeApplication
3340
}
3441
return nil
3542
}
43+
44+
public static var latestXcode: NSRunningApplication? { shared.latestXcode }
3645

3746
public static func createStream() -> AsyncStream<NSRunningApplication?> {
3847
.init { continuation in
@@ -62,3 +71,8 @@ public final class ActiveApplicationMonitor {
6271
}
6372
}
6473
}
74+
75+
extension NSRunningApplication {
76+
public var isXcode: Bool { bundleIdentifier == "com.apple.dt.Xcode" }
77+
}
78+

Core/Sources/Client/AsyncXPCService.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,14 @@ public struct AsyncXPCService {
170170
}
171171
}
172172
}
173+
174+
public func explainSelection(editorContent: EditorContent) async throws -> UpdatedContent? {
175+
try await suggestionRequest(
176+
connection,
177+
editorContent,
178+
{ $0.explainSelection }
179+
)
180+
}
173181
}
174182

175183
struct AutoFinishContinuation<T> {

Core/Sources/Environment/Environment.swift

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -111,33 +111,28 @@ public enum Environment {
111111
}
112112

113113
public static var triggerAction: (_ name: String) async throws -> Void = { name in
114-
var xcodes = [NSRunningApplication]()
115-
var retryCount = 0
116-
// Sometimes runningApplications returns 0 items.
117-
while xcodes.isEmpty, retryCount < 5 {
118-
xcodes = NSRunningApplication
119-
.runningApplications(withBundleIdentifier: "com.apple.dt.Xcode")
120-
if retryCount > 0 { try await Task.sleep(nanoseconds: 10_000_000) }
121-
retryCount += 1
122-
}
123-
124-
guard let activeXcode = xcodes.first(where: { $0.isActive }) else { return }
114+
guard let activeXcode = ActiveApplicationMonitor.activeXcode
115+
?? ActiveApplicationMonitor.latestXcode
116+
else { return }
125117
let bundleName = Bundle.main
126118
.object(forInfoDictionaryKey: "EXTENSION_BUNDLE_NAME") as! String
127119

128120
/// check if menu is open, if not, click the menu item.
129121
let appleScript = """
130122
tell application "System Events"
131-
set proc to item 1 of (processes whose unix id is \(activeXcode.processIdentifier))
132-
tell proc
133-
repeat with theMenu in menus of menu bar 1
134-
set theValue to value of attribute "AXVisibleChildren" of theMenu
135-
if theValue is not {} then
136-
return
137-
end if
138-
end repeat
139-
click menu item "\(name)" of menu 1 of menu item "\(bundleName)" of menu 1 of menu bar item "Editor" of menu bar 1
140-
end tell
123+
set theprocs to every process whose unix id is \(activeXcode.processIdentifier)
124+
repeat with proc in theprocs
125+
set the frontmost of proc to true
126+
tell proc
127+
repeat with theMenu in menus of menu bar 1
128+
set theValue to value of attribute "AXVisibleChildren" of theMenu
129+
if theValue is not {} then
130+
return
131+
end if
132+
end repeat
133+
click menu item "\(name)" of menu 1 of menu item "\(bundleName)" of menu 1 of menu bar item "Editor" of menu bar 1
134+
end tell
135+
end repeat
141136
end tell
142137
"""
143138

0 commit comments

Comments
 (0)