From 69d18ad9b22250401c6980b4068ce397dd5b654f Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Wed, 16 Oct 2024 16:12:17 +0000 Subject: [PATCH] Pre-release 0.25.84 --- Copilot for Xcode/App.swift | 1 - Copilot-for-Xcode-Info.plist | 54 +++++------ .../FeatureSettings/LoggingSettingsView.swift | 63 +++++++++++++ .../SuggesionSettingProxyView.swift | 93 ++++++++++++++----- ...SuggestionSettingsGeneralSectionView.swift | 59 ++++++++---- .../Suggestion/SuggestionSettingsView.swift | 1 + Core/Sources/HostApp/StringConstants.swift | 21 +++++ Core/Sources/HostApp/TabContainer.swift | 6 +- .../LanguageServer/GitHubCopilotService.swift | 6 +- Tool/Sources/Logger/FileLogger.swift | 14 ++- Tool/Sources/Preferences/Keys.swift | 14 ++- 11 files changed, 251 insertions(+), 81 deletions(-) create mode 100644 Core/Sources/HostApp/FeatureSettings/LoggingSettingsView.swift diff --git a/Copilot for Xcode/App.swift b/Copilot for Xcode/App.swift index bd7df55..a00e4f2 100644 --- a/Copilot for Xcode/App.swift +++ b/Copilot for Xcode/App.swift @@ -27,7 +27,6 @@ struct CopilotForXcodeApp: App { .onAppear { UserDefaults.setupDefaultSettings() } - .environment(\.updateChecker, UpdateChecker(hostBundle: Bundle.main)) .copilotIntroSheet() } } diff --git a/Copilot-for-Xcode-Info.plist b/Copilot-for-Xcode-Info.plist index a128dc2..05fd996 100644 --- a/Copilot-for-Xcode-Info.plist +++ b/Copilot-for-Xcode-Info.plist @@ -1,30 +1,32 @@ - - - $(AppIdentifierPrefix) - APPLICATION_SUPPORT_FOLDER - $(APPLICATION_SUPPORT_FOLDER) - BUNDLE_IDENTIFIER_BASE - $(BUNDLE_IDENTIFIER_BASE) - EXTENSION_BUNDLE_NAME - $(EXTENSION_BUNDLE_NAME) - HOST_APP_NAME - $(HOST_APP_NAME) - LANGUAGE_SERVER_PATH - $(LANGUAGE_SERVER_PATH) - NODE_PATH - $(NODE_PATH) - SUEnableAutomaticChecks - YES - SUEnableJavaScript - NO - SUFeedURL - $(SPARKLE_FEED_URL) - SUPublicEDKey - $(SPARKLE_PUBLIC_KEY) - TEAM_ID_PREFIX - $(TeamIdentifierPrefix) - + + + $(AppIdentifierPrefix) + APPLICATION_SUPPORT_FOLDER + $(APPLICATION_SUPPORT_FOLDER) + BUNDLE_IDENTIFIER_BASE + $(BUNDLE_IDENTIFIER_BASE) + EXTENSION_BUNDLE_NAME + $(EXTENSION_BUNDLE_NAME) + HOST_APP_NAME + $(HOST_APP_NAME) + LANGUAGE_SERVER_PATH + $(LANGUAGE_SERVER_PATH) + NODE_PATH + $(NODE_PATH) + SUEnableAutomaticChecks + YES + SUScheduledCheckInterval + 3600 + SUEnableJavaScript + NO + SUFeedURL + $(SPARKLE_FEED_URL) + SUPublicEDKey + $(SPARKLE_PUBLIC_KEY) + TEAM_ID_PREFIX + $(TeamIdentifierPrefix) + diff --git a/Core/Sources/HostApp/FeatureSettings/LoggingSettingsView.swift b/Core/Sources/HostApp/FeatureSettings/LoggingSettingsView.swift new file mode 100644 index 0000000..da311de --- /dev/null +++ b/Core/Sources/HostApp/FeatureSettings/LoggingSettingsView.swift @@ -0,0 +1,63 @@ +import AppKit +import Logger +import Preferences +import SwiftUI + +struct LoggingSettingsView: View { + @AppStorage(\.verboseLoggingEnabled) var verboseLoggingEnabled: Bool + @State private var shouldPresentRestartAlert = false + + var body: some View { + VStack(alignment: .leading) { + Text("Logging") + .bold() + .padding(.leading, 8) + VStack(spacing: .zero) { + HStack(alignment: .center) { + Text("Verbose Logging") + .padding(.horizontal, 8) + Spacer() + Toggle(isOn: $verboseLoggingEnabled) { + } + .toggleStyle(.switch) + .padding(.horizontal, 8) + } + .padding(.vertical, 8) + .onChange(of: verboseLoggingEnabled) { _ in + shouldPresentRestartAlert = true + } + + Divider() + + HStack { + Text("Open Copilot Log Folder") + .font(.body) + Spacer() + Image(systemName: "chevron.right") + } + .onTapGesture { + NSWorkspace.shared.open(URL(fileURLWithPath: FileLoggingLocation.path.string, isDirectory: true)) + } + .foregroundStyle(.primary) + .padding(.horizontal, 8) + .padding(.vertical, 10) + } + .background(Color.gray.opacity(0.1)) + .cornerRadius(8) + } + .padding(.horizontal, 20) + .alert(isPresented: $shouldPresentRestartAlert) { + Alert( + title: Text("Quit And Restart Xcode"), + message: Text( + """ + Logging level changes will take effect the next time Copilot \ + for Xcode is started. To update logging now, please quit \ + Copilot for Xcode and restart Xcode. + """ + ), + dismissButton: .default(Text("OK")) + ) + } + } +} diff --git a/Core/Sources/HostApp/FeatureSettings/Suggestion/SuggesionSettingProxyView.swift b/Core/Sources/HostApp/FeatureSettings/Suggestion/SuggesionSettingProxyView.swift index 7f8488c..9388cbb 100644 --- a/Core/Sources/HostApp/FeatureSettings/Suggestion/SuggesionSettingProxyView.swift +++ b/Core/Sources/HostApp/FeatureSettings/Suggestion/SuggesionSettingProxyView.swift @@ -6,7 +6,6 @@ import Toast import Client struct SuggesionSettingProxyView: View { - class Settings: ObservableObject { @AppStorage("username") var username: String = "" @AppStorage(\.gitHubCopilotProxyUrl) var gitHubCopilotProxyUrl @@ -14,8 +13,6 @@ struct SuggesionSettingProxyView: View { @AppStorage(\.gitHubCopilotProxyPassword) var gitHubCopilotProxyPassword @AppStorage(\.gitHubCopilotUseStrictSSL) var gitHubCopilotUseStrictSSL @AppStorage(\.gitHubCopilotEnterpriseURI) var gitHubCopilotEnterpriseURI - - init() {} } @StateObject var settings = Settings() @@ -23,48 +20,98 @@ struct SuggesionSettingProxyView: View { var body: some View { VStack(alignment: .leading) { - SettingsDivider("Enterprise") + Text(StringConstants.enterprise) + .bold() + .padding(.leading, 8) Form { TextField( text: $settings.gitHubCopilotEnterpriseURI, - prompt: Text("Leave it blank if none is available.") + prompt: Text(StringConstants.leaveBlankPrompt) ) { - Text("Auth provider URL") + Text(StringConstants.authProviderURL) } + .textFieldStyle(PlainTextFieldStyle()) + .multilineTextAlignment(.trailing) } + .padding(8) + .background(Color.gray.opacity(0.1)) + .cornerRadius(6) + .padding(.bottom, 16) - SettingsDivider("Proxy") + Text(StringConstants.proxy) + .bold() + .padding(.leading, 8) - Form { - TextField( - text: $settings.gitHubCopilotProxyUrl, - prompt: Text("http://host:port") - ) { - Text("Proxy URL") + VStack(spacing: 0) { + Form { + TextField( + text: $settings.gitHubCopilotProxyUrl, + prompt: Text(StringConstants.proxyURLPrompt) + ) { + Text(StringConstants.proxyURL) + } + .textFieldStyle(PlainTextFieldStyle()) + .multilineTextAlignment(.trailing) } - TextField(text: $settings.gitHubCopilotProxyUsername) { - Text("Proxy username") + .padding(.horizontal, 16) + .padding(.vertical, 8) + + Divider() + + Form { + TextField(text: $settings.gitHubCopilotProxyUsername, prompt: Text(StringConstants.proxyUsernamePrompt)) { + Text(StringConstants.proxyUsername) + } + .textFieldStyle(PlainTextFieldStyle()) + .multilineTextAlignment(.trailing) } - SecureField(text: $settings.gitHubCopilotProxyPassword) { - Text("Proxy password") + .padding(.horizontal, 16) + .padding(.vertical, 8) + + Divider() + + Form { + SecureField(text: $settings.gitHubCopilotProxyPassword, prompt: Text(StringConstants.proxyPasswordPrompt)) { + Text(StringConstants.proxyPassword) + } + .textFieldStyle(PlainTextFieldStyle()) + .multilineTextAlignment(.trailing) } - Toggle("Proxy strict SSL", isOn: $settings.gitHubCopilotUseStrictSSL) + .padding(.horizontal, 16) + .padding(.vertical, 8) + + Divider() - Button("Refresh configurations") { + HStack { + Text(StringConstants.proxyStrictSSL) + Spacer() + Toggle("", isOn: $settings.gitHubCopilotUseStrictSSL) + .toggleStyle(.switch) + } + .padding(.horizontal, 16) + .padding(.vertical, 8) + } + .background(Color.gray.opacity(0.1)) + .cornerRadius(6) + .padding(.bottom, 8) + + HStack { + Spacer() + Button(StringConstants.refreshConfigurations) { refreshConfiguration() - }.padding(.top, 6) + } } + .padding(.horizontal, 16) + Spacer() } - .textFieldStyle(.roundedBorder) + .padding(16) } - func refreshConfiguration() { NotificationCenter.default.post( name: .gitHubCopilotShouldRefreshEditorInformation, object: nil ) - Task { let service = try getService() do { diff --git a/Core/Sources/HostApp/FeatureSettings/Suggestion/SuggestionSettingsGeneralSectionView.swift b/Core/Sources/HostApp/FeatureSettings/Suggestion/SuggestionSettingsGeneralSectionView.swift index 35f7caa..debc7c8 100644 --- a/Core/Sources/HostApp/FeatureSettings/Suggestion/SuggestionSettingsGeneralSectionView.swift +++ b/Core/Sources/HostApp/FeatureSettings/Suggestion/SuggestionSettingsGeneralSectionView.swift @@ -6,39 +6,62 @@ import XPCShared struct SuggestionSettingsGeneralSectionView: View { final class Settings: ObservableObject { - @AppStorage(\.realtimeSuggestionToggle) - var realtimeSuggestionToggle - @AppStorage(\.suggestionFeatureEnabledProjectList) - var suggestionFeatureEnabledProjectList - @AppStorage(\.acceptSuggestionWithTab) - var acceptSuggestionWithTab + @AppStorage(\.realtimeSuggestionToggle) var realtimeSuggestionToggle + @AppStorage(\.suggestionFeatureEnabledProjectList) var suggestionFeatureEnabledProjectList + @AppStorage(\.acceptSuggestionWithTab) var acceptSuggestionWithTab } @StateObject var settings = Settings() @State var isSuggestionFeatureDisabledLanguageListViewOpen = false var body: some View { - Form { - Toggle(isOn: $settings.realtimeSuggestionToggle) { - Text("Request suggestions in real-time") - } + VStack(alignment: .leading) { + Text(StringConstants.suggestionSettings) + .bold() + .padding(.leading, 8) + + VStack(spacing: .zero) { + HStack(alignment: .center) { + Text(StringConstants.requestSuggestionsInRealTime) + .padding(.horizontal, 8) + Spacer() + Toggle(isOn: $settings.realtimeSuggestionToggle) { + } + .toggleStyle(SwitchToggleStyle(tint: .blue)) + .padding(.horizontal, 8) + } + .padding(.vertical, 8) - Toggle(isOn: $settings.acceptSuggestionWithTab) { - HStack { - Text("Accept suggestions with Tab") + Divider() + + HStack(alignment: .center) { + Text(StringConstants.acceptSuggestionsWithTab) + .padding(.horizontal, 8) + Spacer() + Toggle(isOn: $settings.acceptSuggestionWithTab) { + } + .toggleStyle(SwitchToggleStyle(tint: .blue)) + .padding(.horizontal, 8) } + .padding(.vertical, 8) } + .background(Color.gray.opacity(0.1)) + .cornerRadius(6) + .padding(.bottom, 8) HStack { - Button("Disabled language list") { + Spacer() + Button(StringConstants.disabledLanguageList) { isSuggestionFeatureDisabledLanguageListViewOpen = true } - }.sheet(isPresented: $isSuggestionFeatureDisabledLanguageListViewOpen) { - SuggestionFeatureDisabledLanguageListView( - isOpen: $isSuggestionFeatureDisabledLanguageListViewOpen - ) } + .padding(.horizontal) + .sheet(isPresented: $isSuggestionFeatureDisabledLanguageListViewOpen) { + SuggestionFeatureDisabledLanguageListView(isOpen: $isSuggestionFeatureDisabledLanguageListViewOpen) + } + Spacer() } + .padding(16) } } diff --git a/Core/Sources/HostApp/FeatureSettings/Suggestion/SuggestionSettingsView.swift b/Core/Sources/HostApp/FeatureSettings/Suggestion/SuggestionSettingsView.swift index f5a99ac..8d2f05a 100644 --- a/Core/Sources/HostApp/FeatureSettings/Suggestion/SuggestionSettingsView.swift +++ b/Core/Sources/HostApp/FeatureSettings/Suggestion/SuggestionSettingsView.swift @@ -9,6 +9,7 @@ struct SuggestionSettingsView: View { ScrollView { SuggestionSettingsGeneralSectionView() SuggesionSettingProxyView() + LoggingSettingsView() }.padding() } } diff --git a/Core/Sources/HostApp/StringConstants.swift b/Core/Sources/HostApp/StringConstants.swift index 5740f0f..ca47928 100644 --- a/Core/Sources/HostApp/StringConstants.swift +++ b/Core/Sources/HostApp/StringConstants.swift @@ -1,4 +1,5 @@ struct StringConstants { + // General Tab Strings static let rightsReserved = "GitHub. All rights reserved." static let appName = "GitHub Copilot for Xcode" static let languageServerVersion = "Language Server Version:" @@ -28,4 +29,24 @@ struct StringConstants { static let copilotDocumentation = "View Copilot Documentation" static let copilotFeedbackForum = "View Copilot Feedback Forum" static let loading = "Loading.." + +// Feature Tab Settings Strings + static let suggestionSettings = "Suggestion Settings" + static let requestSuggestionsInRealTime = "Request suggestions in real-time" + static let acceptSuggestionsWithTab = "Accept suggestions with Tab" + static let disabledLanguageList = "Disabled language list" + + // Proxy String + static let enterprise = "Enterprise" + static let leaveBlankPrompt = "Leave it blank if none is available." + static let authProviderURL = "Auth provider URL" + static let proxy = "Proxy" + static let proxyURLPrompt = "http://host:port" + static let proxyURL = "Proxy URL" + static let proxyUsernamePrompt = "username" + static let proxyUsername = "Proxy username" + static let proxyPasswordPrompt = "password" + static let proxyPassword = "Proxy password" + static let proxyStrictSSL = "Proxy strict SSL" + static let refreshConfigurations = "Refresh configurations" } diff --git a/Core/Sources/HostApp/TabContainer.swift b/Core/Sources/HostApp/TabContainer.swift index e40db63..b60cc48 100644 --- a/Core/Sources/HostApp/TabContainer.swift +++ b/Core/Sources/HostApp/TabContainer.swift @@ -40,8 +40,8 @@ public struct TabContainer: View { ) FeatureSettingsView().tabBarItem( tag: 2, - title: "Feature", - image: "star.circle" + title: "Advanced", + image: "gearshape.2.fill" ) } .environment(\.tabBarTabTag, tag) @@ -201,7 +201,7 @@ private extension EnvironmentValues { } struct UpdateCheckerKey: EnvironmentKey { - static var defaultValue: UpdateChecker = .init(hostBundle: nil) + static var defaultValue: UpdateChecker = .init(hostBundle: Bundle.main) } public extension EnvironmentValues { diff --git a/Tool/Sources/GitHubCopilotService/LanguageServer/GitHubCopilotService.swift b/Tool/Sources/GitHubCopilotService/LanguageServer/GitHubCopilotService.swift index 4b947b9..6267fb6 100644 --- a/Tool/Sources/GitHubCopilotService/LanguageServer/GitHubCopilotService.swift +++ b/Tool/Sources/GitHubCopilotService/LanguageServer/GitHubCopilotService.swift @@ -146,7 +146,11 @@ public class GitHubCopilotBaseService { // Set debug port and verbose when running in debug let environment: [String: String] = ["HOME": home, "GH_COPILOT_DEBUG_UI_PORT": "8080", "GH_COPILOT_VERBOSE": "true"] #else - let environment: [String: String] = ["HOME": home] + let environment: [String: String] = if UserDefaults.shared.value(for: \.verboseLoggingEnabled) { + ["HOME": home, "GH_COPILOT_VERBOSE": "true"] + } else { + ["HOME": home] + } #endif let executionParams = Process.ExecutionParameters( diff --git a/Tool/Sources/Logger/FileLogger.swift b/Tool/Sources/Logger/FileLogger.swift index 85f85f9..e7c2a64 100644 --- a/Tool/Sources/Logger/FileLogger.swift +++ b/Tool/Sources/Logger/FileLogger.swift @@ -1,6 +1,15 @@ import Foundation import System +public final class FileLoggingLocation { + public static let path = { + FilePath(stringLiteral: NSHomeDirectory()) + .appending("Library") + .appending("Logs") + .appending("GitHubCopilot") + }() +} + final class FileLogger { private let timestampFormat = Date.ISO8601FormatStyle.iso8601 .year() @@ -38,10 +47,7 @@ actor FileLoggerImplementation { private var logHandle: FileHandle? public init() { - logDir = FilePath(stringLiteral: NSHomeDirectory()) - .appending("Library") - .appending("Logs") - .appending("GitHubCopilot") + logDir = FileLoggingLocation.path logName = "\(logBaseName).\(logExtension)" lockFilePath = logDir.appending(logName + ".lock") } diff --git a/Tool/Sources/Preferences/Keys.swift b/Tool/Sources/Preferences/Keys.swift index 4772feb..3e4a4c1 100644 --- a/Tool/Sources/Preferences/Keys.swift +++ b/Tool/Sources/Preferences/Keys.swift @@ -527,27 +527,31 @@ public extension UserDefaultPreferenceKeys { } } -// MARK: - Feature +// MARK: - Advanced Features public extension UserDefaultPreferenceKeys { var gitHubCopilotProxyUrl: PreferenceKey { .init(defaultValue: "", key: "GitHubCopilotProxyUrl") } - + var gitHubCopilotUseStrictSSL: PreferenceKey { .init(defaultValue: true, key: "GitHubCopilotUseStrictSSL") } - + var gitHubCopilotProxyUsername: PreferenceKey { .init(defaultValue: "", key: "GitHubCopilotProxyUsername") } - + var gitHubCopilotProxyPassword: PreferenceKey { .init(defaultValue: "", key: "GitHubCopilotProxyPassword") } - + var gitHubCopilotEnterpriseURI: PreferenceKey { .init(defaultValue: "", key: "GitHubCopilotEnterpriseURI") } + + var verboseLoggingEnabled: PreferenceKey { + .init(defaultValue: false, key: "VerboseLoggingEnabled") + } }