From 887f789f9ed273f619c88e6e264cc0dcb1c83142 Mon Sep 17 00:00:00 2001
From: GitHub Actions
Date: Mon, 4 Nov 2024 19:43:08 +0000
Subject: [PATCH] Pre-release 0.27.93
---
.../AdvancedSettings/EnterpriseSection.swift | 29 +++++++++++++++--
.../AdvancedSettings/ProxySection.swift | 21 ++++++------
.../CopilotConnectionView.swift | 5 ++-
.../SharedComponents/DebouncedBinding.swift | 25 +++++++++++++++
DEVELOPMENT.md | 4 +++
ExtensionService/AuthStatusChecker.swift | 4 +--
README.md | 21 +++++++++---
TROUBLESHOOTING.md | 32 +++++++++++++++++--
.../LanguageServer/GitHubCopilotRequest.swift | 2 --
.../LanguageServer/GitHubCopilotService.swift | 2 +-
10 files changed, 116 insertions(+), 29 deletions(-)
create mode 100644 Core/Sources/HostApp/SharedComponents/DebouncedBinding.swift
diff --git a/Core/Sources/HostApp/AdvancedSettings/EnterpriseSection.swift b/Core/Sources/HostApp/AdvancedSettings/EnterpriseSection.swift
index ee90c35..bcd0adf 100644
--- a/Core/Sources/HostApp/AdvancedSettings/EnterpriseSection.swift
+++ b/Core/Sources/HostApp/AdvancedSettings/EnterpriseSection.swift
@@ -1,17 +1,42 @@
+import Combine
import SwiftUI
+import Toast
struct EnterpriseSection: View {
@AppStorage(\.gitHubCopilotEnterpriseURI) var gitHubCopilotEnterpriseURI
+ @Environment(\.toast) var toast
var body: some View {
SettingsSection(title: "Enterprise") {
SettingsTextField(
title: "Auth provider URL",
- prompt: "Leave it blank if none is available.",
- text: $gitHubCopilotEnterpriseURI
+ prompt: "https://your-enterprise.ghe.com",
+ text: DebouncedBinding($gitHubCopilotEnterpriseURI, handler: urlChanged).binding
)
}
}
+
+ func urlChanged(_ url: String) {
+ if !url.isEmpty {
+ validateAuthURL(url)
+ }
+ NotificationCenter.default.post(
+ name: .gitHubCopilotShouldRefreshEditorInformation,
+ object: nil
+ )
+ }
+
+ func validateAuthURL(_ url: String) {
+ let maybeURL = URL(string: url)
+ guard let parsedURl = maybeURL else {
+ toast("Invalid URL", .error)
+ return
+ }
+ if parsedURl.scheme != "https" {
+ toast("URL scheme must be https://", .error)
+ return
+ }
+ }
}
#Preview {
diff --git a/Core/Sources/HostApp/AdvancedSettings/ProxySection.swift b/Core/Sources/HostApp/AdvancedSettings/ProxySection.swift
index 27b1ac2..168bdb1 100644
--- a/Core/Sources/HostApp/AdvancedSettings/ProxySection.swift
+++ b/Core/Sources/HostApp/AdvancedSettings/ProxySection.swift
@@ -15,33 +15,30 @@ struct ProxySection: View {
SettingsTextField(
title: "Proxy URL",
prompt: "http://host:port",
- text: $gitHubCopilotProxyUrl
+ text: wrapBinding($gitHubCopilotProxyUrl)
)
SettingsTextField(
title: "Proxy username",
prompt: "username",
- text: $gitHubCopilotProxyUsername
+ text: wrapBinding($gitHubCopilotProxyUsername)
)
SettingsSecureField(
title: "Proxy password",
prompt: "password",
- text: $gitHubCopilotProxyPassword
+ text: wrapBinding($gitHubCopilotProxyPassword)
)
SettingsToggle(
title: "Proxy strict SSL",
- isOn: $gitHubCopilotUseStrictSSL
+ isOn: wrapBinding($gitHubCopilotUseStrictSSL)
)
- } footer: {
- HStack {
- Spacer()
- Button("Refresh configurations") {
- refreshConfiguration()
- }
- }
}
}
- func refreshConfiguration() {
+ private func wrapBinding(_ b: Binding) -> Binding {
+ DebouncedBinding(b, handler: refreshConfiguration).binding
+ }
+
+ func refreshConfiguration(_: Any) {
NotificationCenter.default.post(
name: .gitHubCopilotShouldRefreshEditorInformation,
object: nil
diff --git a/Core/Sources/HostApp/GeneralSettings/CopilotConnectionView.swift b/Core/Sources/HostApp/GeneralSettings/CopilotConnectionView.swift
index 8d0b51c..43a4aa8 100644
--- a/Core/Sources/HostApp/GeneralSettings/CopilotConnectionView.swift
+++ b/Core/Sources/HostApp/GeneralSettings/CopilotConnectionView.swift
@@ -6,7 +6,6 @@ struct CopilotConnectionView: View {
@Environment(\.toast) var toast
@StateObject var viewModel = GitHubCopilotViewModel()
- @State var waitingForSignIn = false
let store: StoreOf
var body: some View {
@@ -24,13 +23,13 @@ struct CopilotConnectionView: View {
title: "GitHub Account Status Permissions",
subtitle: "GitHub Connection: \(viewModel.status?.description ?? "Loading...")"
) {
- if viewModel.isRunningAction || waitingForSignIn {
+ if viewModel.isRunningAction || viewModel.waitingForSignIn {
ProgressView().controlSize(.small)
}
Button("Refresh Connection") {
viewModel.checkStatus()
}
- if waitingForSignIn {
+ if viewModel.waitingForSignIn {
Button("Cancel") {
viewModel.cancelWaiting()
}
diff --git a/Core/Sources/HostApp/SharedComponents/DebouncedBinding.swift b/Core/Sources/HostApp/SharedComponents/DebouncedBinding.swift
new file mode 100644
index 0000000..6b4224b
--- /dev/null
+++ b/Core/Sources/HostApp/SharedComponents/DebouncedBinding.swift
@@ -0,0 +1,25 @@
+import Combine
+import SwiftUI
+
+class DebouncedBinding {
+ private let subject = PassthroughSubject()
+ private let cancellable: AnyCancellable
+ private let wrappedBinding: Binding
+
+ init(_ binding: Binding, handler: @escaping (T) -> Void) {
+ self.wrappedBinding = binding
+ self.cancellable = subject
+ .debounce(for: .seconds(1.0), scheduler: RunLoop.main)
+ .sink { handler($0) }
+ }
+
+ var binding: Binding {
+ return Binding(
+ get: { self.wrappedBinding.wrappedValue },
+ set: {
+ self.wrappedBinding.wrappedValue = $0
+ self.subject.send($0)
+ }
+ )
+ }
+}
diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md
index 4c8818a..877cdd9 100644
--- a/DEVELOPMENT.md
+++ b/DEVELOPMENT.md
@@ -6,8 +6,12 @@ Requires Node installed and `npm` available on your system path, e.g.
```sh
sudo ln -s `which npm` /usr/local/bin
+sudo ln -s `which node` /usr/local/bin
```
+For context, this is used by an Xcode run script as part of the build. Run
+scripts use a very limited path to resolve commands.
+
## Targets
### Copilot for Xcode
diff --git a/ExtensionService/AuthStatusChecker.swift b/ExtensionService/AuthStatusChecker.swift
index d144ed9..6da7071 100644
--- a/ExtensionService/AuthStatusChecker.swift
+++ b/ExtensionService/AuthStatusChecker.swift
@@ -15,11 +15,11 @@ class AuthStatusChecker {
Task {
do {
let status = try await self.getCurrentAuthStatus()
- DispatchQueue.main.async {
+ Task { @MainActor in
notify(status.description, status == .ok)
}
} catch {
- DispatchQueue.main.async {
+ Task { @MainActor in
notify("\(error)", false)
}
}
diff --git a/README.md b/README.md
index 82eb3ea..255c74f 100644
--- a/README.md
+++ b/README.md
@@ -35,12 +35,14 @@ Use of the GitHub Copilot Xcode Extension is subject to [GitHub's Pre-Release Te
-1. A background item will be added for the application to be able to start itself when Xcode starts.
+1. A background item will be added to enable Copilot to start when Xcode is opened.
-1. Two permissions are required: `Accessibility` and `Xcode Source Editor Extension`.
+1. Two permissions are required: `Accessibility` and `Xcode Source Editor
+ Extension`. For more on why these permissions are required see
+ [TROUBLESHOOTING.md](./TROUBLESHOOTING.md).
The first time the application is run the `Accessibility` permission should be requested:
@@ -57,7 +59,9 @@ Use of the GitHub Copilot Xcode Extension is subject to [GitHub's Pre-Release Te
-1. After granting the extension permission, please restart Xcode so the `Github Copilot` menu is available under the Xcode `Editor` menu.
+1. After granting the extension permission, please restart Xcode to ensure the
+ `Github Copilot` menu is available and not disabled under the Xcode `Editor`
+ menu.
@@ -71,7 +75,16 @@ Use of the GitHub Copilot Xcode Extension is subject to [GitHub's Pre-Release Te
-1. To install updates, click `Check for Updates` from the menu item or in the settings application. After installing a new version, Xcode must be restarted to use the new version correctly. New versions can also be installed from `dmg` files downloaded from the releases page. When installing a new version via `dmg`, the application must be run manually the first time to accept the downloaded from the internet warning.
+1. To install updates, click `Check for Updates` from the menu item or in the
+ settings application.
+
+ After installing a new version, Xcode must be restarted to use the new
+ version correctly.
+
+ New versions can also be installed from `dmg` files downloaded from the
+ releases page. When installing a new version via `dmg`, the application must
+ be run manually the first time to accept the downloaded from the internet
+ warning.
1. To avoid confusion, we recommend disabling `Predictive code completion` under
`Xcode` > `Preferences` > `Text Editing` > `Editing`.
diff --git a/TROUBLESHOOTING.md b/TROUBLESHOOTING.md
index 1d127f8..98fdca7 100644
--- a/TROUBLESHOOTING.md
+++ b/TROUBLESHOOTING.md
@@ -15,7 +15,8 @@ common issues:
then Xcode needs to be restarted to enable the extension.
3. Need more help? If these steps don't resolve the issue, please [open an
- issue](https://github.com/github/CopilotForXcode/issues/new/choose).
+ issue](https://github.com/github/CopilotForXcode/issues/new/choose). Make
+ sure to [include logs](#logs) and any other relevant information.
## Extension Permission
@@ -34,8 +35,33 @@ Or you can navigate to the permission manually depending on your OS version:
## Accessibility Permission
-GitHub Copilot for Xcode requires accessibility permission to receive
-information from the active Xcode editor.
+GitHub Copilot for Xcode requires the accessibility permission to receive
+real-time updates from the active Xcode editor. [The XcodeKit
+API](https://developer.apple.com/documentation/xcodekit)
+enabled by the Xcode Source Editor extension permission only provides
+information when manually triggered by the user. In order to generate
+suggestions as you type, the accessibility permission is used read the
+Xcode editor content in real-time.
+
+The accessibility permission is also used to accept suggestions when `tab` is
+pressed.
+
+The accessibility permission is __not__ used to read or write to any
+applications besides Xcode. There are no granular options for the permission,
+but you can audit the usage in this repository: search for `CGEvent` and `AX`*.
Enable in System Settings under `Privacy & Security` > `Accessibility` >
`GitHub Copilot for Xcode Extension` and turn on the toggle.
+
+## Logs
+
+Logs can be found in `~/Library/Logs/GitHubCopilot/` the most recent log file
+is:
+
+```
+~/Library/Logs/GitHubCopilot/github-copilot-for-xcode.log
+```
+
+To enable verbose logging, open the GitHub Copilot for Xcode settings and enable
+`Verbose Logging` in the `Advanced` tab. After enabling verbose logging, restart
+Copilot for Xcode for the change to take effect.
diff --git a/Tool/Sources/GitHubCopilotService/LanguageServer/GitHubCopilotRequest.swift b/Tool/Sources/GitHubCopilotService/LanguageServer/GitHubCopilotRequest.swift
index 159384b..1c7f252 100644
--- a/Tool/Sources/GitHubCopilotService/LanguageServer/GitHubCopilotRequest.swift
+++ b/Tool/Sources/GitHubCopilotService/LanguageServer/GitHubCopilotRequest.swift
@@ -67,13 +67,11 @@ public func editorConfiguration() -> JSONValue {
d["proxyAuthorization"] = .string(proxyAuthorization)
}
d["proxyStrictSSL"] = .bool(UserDefaults.shared.value(for: \.gitHubCopilotUseStrictSSL))
- if d.isEmpty { return nil }
return .hash(d)
}
var authProvider: JSONValue? {
let enterpriseURI = UserDefaults.shared.value(for: \.gitHubCopilotEnterpriseURI)
- if enterpriseURI.isEmpty { return nil }
return .hash([ "uri": .string(enterpriseURI) ])
}
diff --git a/Tool/Sources/GitHubCopilotService/LanguageServer/GitHubCopilotService.swift b/Tool/Sources/GitHubCopilotService/LanguageServer/GitHubCopilotService.swift
index a80064e..a2b6578 100644
--- a/Tool/Sources/GitHubCopilotService/LanguageServer/GitHubCopilotService.swift
+++ b/Tool/Sources/GitHubCopilotService/LanguageServer/GitHubCopilotService.swift
@@ -314,7 +314,7 @@ public final class GitHubCopilotService: GitHubCopilotBaseService,
tabSize: tabSize,
insertSpaces: !usesTabsForIndentation
),
- context: .init(triggerKind: .automatic)
+ context: .init(triggerKind: .invoked)
)))
.items
.compactMap { (item: _) -> CodeSuggestion? in