From 2a8cc59827170fb94610c0464fc1dc24cc59ce2b Mon Sep 17 00:00:00 2001 From: Shota Abe Date: Fri, 24 Mar 2023 20:51:57 +0900 Subject: [PATCH 1/6] =?UTF-8?q?=E3=83=95=E3=83=AD=E3=83=BC=E3=83=86?= =?UTF-8?q?=E3=82=A3=E3=83=B3=E3=82=B0=E3=82=A6=E3=82=A3=E3=83=B3=E3=83=89?= =?UTF-8?q?=E3=82=A6=E3=82=92=E9=96=8B=E3=81=91=E3=82=8B=E3=82=88=E3=81=86?= =?UTF-8?q?=E3=81=AB=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ChatGPTForXcode/AppDelegate.swift | 17 +++++ ChatGPTForXcode/ChatGPTForXcodeApp.swift | 21 +++++- ChatGPTForXcode/Info.plist | 15 ++++- ChatGPTForXcode/ToolbarDelegate.swift | 61 ++++++++++++++++++ ChatGPTForXcode/WindowLauncher.swift | 64 +++++++++++++++++++ .../BaseCommand.swift | 4 ++ 6 files changed, 177 insertions(+), 5 deletions(-) create mode 100644 ChatGPTForXcode/AppDelegate.swift create mode 100644 ChatGPTForXcode/ToolbarDelegate.swift create mode 100644 ChatGPTForXcode/WindowLauncher.swift diff --git a/ChatGPTForXcode/AppDelegate.swift b/ChatGPTForXcode/AppDelegate.swift new file mode 100644 index 0000000..23f0439 --- /dev/null +++ b/ChatGPTForXcode/AppDelegate.swift @@ -0,0 +1,17 @@ +// +// AppDelegate.swift +// ChatGPTForXcode +// +// Created by 安部翔太 on 2023/03/24. +// + +import SwiftUI + +class AppDelegate: NSObject, NSApplicationDelegate { + + func application(_ application: NSApplication, open urls: [URL]) { + print(urls) + WindowLauncher.openChatPanel() + WindowLauncher.openConfigurationView() + } +} diff --git a/ChatGPTForXcode/ChatGPTForXcodeApp.swift b/ChatGPTForXcode/ChatGPTForXcodeApp.swift index afd2f23..e506914 100644 --- a/ChatGPTForXcode/ChatGPTForXcodeApp.swift +++ b/ChatGPTForXcode/ChatGPTForXcodeApp.swift @@ -10,10 +10,25 @@ import SwiftUI @main struct ChatGPTForXcodeApp: App { + @NSApplicationDelegateAdaptor(AppDelegate.self) var delegate + var body: some Scene { - WindowGroup { - ConfigurationView() + // WindowGroup { + // ConfigurationView() + // } + // .windowResizability(.contentSize) + + MenuBarExtra { + Button { + print("button tapped!") + } label: { + Text("Button") + } + } label: { + Image(systemName: "bubble.left.fill") } - .windowResizability(.contentSize) + } } + +// chat-gpt-for-xcode:// diff --git a/ChatGPTForXcode/Info.plist b/ChatGPTForXcode/Info.plist index 3d4c1e5..304feaa 100644 --- a/ChatGPTForXcode/Info.plist +++ b/ChatGPTForXcode/Info.plist @@ -2,7 +2,18 @@ - IDEDidComputeMac32BitWarning - + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLSchemes + + chat-gpt-for-xcode + + + + IDEDidComputeMac32BitWarning + diff --git a/ChatGPTForXcode/ToolbarDelegate.swift b/ChatGPTForXcode/ToolbarDelegate.swift new file mode 100644 index 0000000..b1d8589 --- /dev/null +++ b/ChatGPTForXcode/ToolbarDelegate.swift @@ -0,0 +1,61 @@ +// +// ToolbarDelegate.swift +// ChatGPTForXcode +// +// Created by 安部翔太 on 2023/03/24. +// + +import SwiftUI + +final class ToolbarDelegate: NSObject {} + +extension NSToolbarItem.Identifier { + static let openAboutPanel = NSToolbarItem.Identifier("com.Avis.ChatGPTForXcode.openAboutPanel") +} + +extension ToolbarDelegate: NSToolbarDelegate { + + func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { + let identifiers: [NSToolbarItem.Identifier] = [ + .flexibleSpace, + .openAboutPanel + ] + return identifiers + } + + func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { + return toolbarDefaultItemIdentifiers(toolbar) + } + + func toolbar(_ toolbar: NSToolbar, + itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, + willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? { + + var toolbarItem: NSToolbarItem? + + switch itemIdentifier { + case .openAboutPanel: + let item = NSToolbarItem(itemIdentifier: itemIdentifier) + item.image = NSImage(symbolName: "info.circle", variableValue: 20) + item.label = "Open AboutPanel" + // item.action = #selector(RecipeDetailViewController.editRecipe(_:)) + item.target = nil + // item.view = NSHostingView(rootView: { + // Button { + // NSApplication.shared.orderFrontStandardAboutPanel( + // options: [NSApplication.AboutPanelOptionKey(rawValue: "Copyright"): "© 2023 Avis Inc"] + // ) + // } label: { + // Image(systemName: "info.circle") + // } + // .fontWeight(.bold) + // }()) + toolbarItem = item + + default: + toolbarItem = nil + } + + return toolbarItem + } +} diff --git a/ChatGPTForXcode/WindowLauncher.swift b/ChatGPTForXcode/WindowLauncher.swift new file mode 100644 index 0000000..e6a0f6d --- /dev/null +++ b/ChatGPTForXcode/WindowLauncher.swift @@ -0,0 +1,64 @@ +// +// WindowLauncher.swift +// ChatGPTForXcode +// +// Created by 安部翔太 on 2023/03/24. +// + +import SwiftUI + +struct WindowLauncher { + static func openChatPanel() { + let view = Text("hello") + .frame(minWidth: 200, minHeight: 200) + .frame(maxWidth: .infinity, maxHeight: .infinity) + let controller = NSHostingController(rootView: view) + + let panel = NSPanel( + contentRect: .zero, + styleMask: [ + .closable, + .miniaturizable, + .nonactivatingPanel, + .titled, + .resizable + ], + backing: .buffered, + defer: false) + panel.contentViewController = controller + panel.level = .floating + panel.collectionBehavior = [ + .canJoinAllSpaces, + .fullScreenAuxiliary + ] + panel.isMovableByWindowBackground = true + panel.center() + panel.makeKeyAndOrderFront(nil) + } + + static func openConfigurationView() { + let view = ConfigurationView() + let controller = NSHostingController(rootView: view) + + let window = NSWindow( + contentRect: .zero, + styleMask: [ + .closable, + .miniaturizable, + .titled, + .resizable + ], + backing: .buffered, + defer: false) + window.contentViewController = controller + window.toolbar = { + let toolbar = NSToolbar(identifier: "main") + let toolbarDelegate = ToolbarDelegate() + toolbar.delegate = toolbarDelegate + return toolbar + }() + window.toolbarStyle = .unified + window.center() + window.makeKeyAndOrderFront(nil) + } +} diff --git a/ChatGPTForXcodeEditorExtension/BaseCommand.swift b/ChatGPTForXcodeEditorExtension/BaseCommand.swift index b43a3f2..1fd3652 100644 --- a/ChatGPTForXcodeEditorExtension/BaseCommand.swift +++ b/ChatGPTForXcodeEditorExtension/BaseCommand.swift @@ -8,6 +8,7 @@ import Foundation import XcodeKit +import AppKit class BaseCommand: NSObject, XCSourceEditorCommand { func perform( @@ -71,6 +72,9 @@ class BaseCommand: NSObject, XCSourceEditorCommand { let comments = [markerComment, reviewComment] let result = comments.joined(separator: "\n") buffer.lines.insert(result, at: selection.start.line) + if let url = URL(string: "chat-gpt-for-xcode://") { + NSWorkspace.shared.open(url) + } completionHandler(nil) } catch { completionHandler(error) From 37125c32372e79b8f5fcb3676050658d8ba73d58 Mon Sep 17 00:00:00 2001 From: Shota Abe Date: Sat, 25 Mar 2023 09:43:58 +0900 Subject: [PATCH 2/6] =?UTF-8?q?=E6=8B=A1=E5=BC=B5=E6=A9=9F=E8=83=BD?= =?UTF-8?q?=E3=81=8B=E3=82=89=E3=82=A2=E3=83=97=E3=83=AA=E3=81=AB=E6=96=87?= =?UTF-8?q?=E5=AD=97=E5=88=97=E3=82=92=E6=B8=A1=E3=81=9B=E3=82=8B=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ChatGPTForXcode/AppDelegate.swift | 17 ---- ChatGPTForXcode/ChatGPTForXcodeApp.swift | 84 +++++++++++++++++-- ChatGPTForXcode/ChatView.swift | 39 +++++++++ ChatGPTForXcode/ToolbarDelegate.swift | 61 -------------- ChatGPTForXcode/WindowLauncher.swift | 64 -------------- .../BaseCommand.swift | 8 +- 6 files changed, 120 insertions(+), 153 deletions(-) delete mode 100644 ChatGPTForXcode/AppDelegate.swift create mode 100644 ChatGPTForXcode/ChatView.swift delete mode 100644 ChatGPTForXcode/ToolbarDelegate.swift delete mode 100644 ChatGPTForXcode/WindowLauncher.swift diff --git a/ChatGPTForXcode/AppDelegate.swift b/ChatGPTForXcode/AppDelegate.swift deleted file mode 100644 index 23f0439..0000000 --- a/ChatGPTForXcode/AppDelegate.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// AppDelegate.swift -// ChatGPTForXcode -// -// Created by 安部翔太 on 2023/03/24. -// - -import SwiftUI - -class AppDelegate: NSObject, NSApplicationDelegate { - - func application(_ application: NSApplication, open urls: [URL]) { - print(urls) - WindowLauncher.openChatPanel() - WindowLauncher.openConfigurationView() - } -} diff --git a/ChatGPTForXcode/ChatGPTForXcodeApp.swift b/ChatGPTForXcode/ChatGPTForXcodeApp.swift index e506914..1d31747 100644 --- a/ChatGPTForXcode/ChatGPTForXcodeApp.swift +++ b/ChatGPTForXcode/ChatGPTForXcodeApp.swift @@ -10,19 +10,13 @@ import SwiftUI @main struct ChatGPTForXcodeApp: App { - @NSApplicationDelegateAdaptor(AppDelegate.self) var delegate - + @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate : AppDelegate var body: some Scene { - // WindowGroup { - // ConfigurationView() - // } - // .windowResizability(.contentSize) - MenuBarExtra { Button { - print("button tapped!") + NSApplication.shared.terminate(self) } label: { - Text("Button") + Text("Quit") } } label: { Image(systemName: "bubble.left.fill") @@ -32,3 +26,75 @@ struct ChatGPTForXcodeApp: App { } // chat-gpt-for-xcode:// + +class AppDelegate: NSObject, NSApplicationDelegate { + func applicationDidFinishLaunching(_ notification: Notification) { + if NSApplication.shared.windows.filter({$0.identifier == .init("configurationWindow")}).first != nil { + return + } + let view = ConfigurationView() + let controller = NSHostingController(rootView: view) + + let window = NSWindow( + contentRect: .zero, + styleMask: [ + .closable, + .miniaturizable, + .titled, + .resizable + ], + backing: .buffered, + defer: false) + window.identifier = .init("configurationWindow") + window.contentViewController = controller + window.toolbarStyle = .unified + window.toolbar = .init() + window.center() + window.makeKeyAndOrderFront(nil) + } + + func application(_ application: NSApplication, open urls: [URL]) { + print(urls) + if let url = urls.first { + openChatPanel(url: url) + } + } + + let chatViewModel = ChatViewModel() + + private func openChatPanel(url: URL) { + guard let query = url.query, + let text = query.removingPercentEncoding + else { return } + + chatViewModel.messages.append(.init(text: text)) + + if NSApplication.shared.windows.filter({$0.identifier == .init("chatPanel")}).first != nil { + return + } + + let view = ChatView(viewModel: self.chatViewModel) + let controller = NSHostingController(rootView: view) + + let panel = NSPanel( + contentRect: .zero, + styleMask: [ + .closable, + .miniaturizable, + .nonactivatingPanel, + .titled, + .resizable + ], + backing: .buffered, + defer: false) + panel.identifier = .init("chatPanel") + panel.contentViewController = controller + panel.level = .floating + panel.collectionBehavior = [ + .canJoinAllSpaces, + .fullScreenAuxiliary + ] + panel.center() + panel.makeKeyAndOrderFront(nil) + } +} diff --git a/ChatGPTForXcode/ChatView.swift b/ChatGPTForXcode/ChatView.swift new file mode 100644 index 0000000..ca1dd61 --- /dev/null +++ b/ChatGPTForXcode/ChatView.swift @@ -0,0 +1,39 @@ +// +// ChatView.swift +// ChatGPTForXcode +// +// Created by 安部翔太 on 2023/03/25. +// + +import SwiftUI + +struct Message: Identifiable { + let id = UUID() + let text: String +} + +final class ChatViewModel: ObservableObject { + @Published var messages: [Message] = [] +} + +struct ChatView: View { + @StateObject var viewModel: ChatViewModel + var body: some View { + List(viewModel.messages) { message in + VStack(spacing: 4) { + Text(message.text) + .textSelection(.enabled) + .frame(maxWidth: .infinity, alignment: .leading) + Divider() + } + } + .frame(minWidth: 200, minHeight: 200) + .frame(maxWidth: .infinity, maxHeight: .infinity) + } +} + +struct ChatView_Previews: PreviewProvider { + static var previews: some View { + ChatView(viewModel: .init()) + } +} diff --git a/ChatGPTForXcode/ToolbarDelegate.swift b/ChatGPTForXcode/ToolbarDelegate.swift deleted file mode 100644 index b1d8589..0000000 --- a/ChatGPTForXcode/ToolbarDelegate.swift +++ /dev/null @@ -1,61 +0,0 @@ -// -// ToolbarDelegate.swift -// ChatGPTForXcode -// -// Created by 安部翔太 on 2023/03/24. -// - -import SwiftUI - -final class ToolbarDelegate: NSObject {} - -extension NSToolbarItem.Identifier { - static let openAboutPanel = NSToolbarItem.Identifier("com.Avis.ChatGPTForXcode.openAboutPanel") -} - -extension ToolbarDelegate: NSToolbarDelegate { - - func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { - let identifiers: [NSToolbarItem.Identifier] = [ - .flexibleSpace, - .openAboutPanel - ] - return identifiers - } - - func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { - return toolbarDefaultItemIdentifiers(toolbar) - } - - func toolbar(_ toolbar: NSToolbar, - itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, - willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? { - - var toolbarItem: NSToolbarItem? - - switch itemIdentifier { - case .openAboutPanel: - let item = NSToolbarItem(itemIdentifier: itemIdentifier) - item.image = NSImage(symbolName: "info.circle", variableValue: 20) - item.label = "Open AboutPanel" - // item.action = #selector(RecipeDetailViewController.editRecipe(_:)) - item.target = nil - // item.view = NSHostingView(rootView: { - // Button { - // NSApplication.shared.orderFrontStandardAboutPanel( - // options: [NSApplication.AboutPanelOptionKey(rawValue: "Copyright"): "© 2023 Avis Inc"] - // ) - // } label: { - // Image(systemName: "info.circle") - // } - // .fontWeight(.bold) - // }()) - toolbarItem = item - - default: - toolbarItem = nil - } - - return toolbarItem - } -} diff --git a/ChatGPTForXcode/WindowLauncher.swift b/ChatGPTForXcode/WindowLauncher.swift deleted file mode 100644 index e6a0f6d..0000000 --- a/ChatGPTForXcode/WindowLauncher.swift +++ /dev/null @@ -1,64 +0,0 @@ -// -// WindowLauncher.swift -// ChatGPTForXcode -// -// Created by 安部翔太 on 2023/03/24. -// - -import SwiftUI - -struct WindowLauncher { - static func openChatPanel() { - let view = Text("hello") - .frame(minWidth: 200, minHeight: 200) - .frame(maxWidth: .infinity, maxHeight: .infinity) - let controller = NSHostingController(rootView: view) - - let panel = NSPanel( - contentRect: .zero, - styleMask: [ - .closable, - .miniaturizable, - .nonactivatingPanel, - .titled, - .resizable - ], - backing: .buffered, - defer: false) - panel.contentViewController = controller - panel.level = .floating - panel.collectionBehavior = [ - .canJoinAllSpaces, - .fullScreenAuxiliary - ] - panel.isMovableByWindowBackground = true - panel.center() - panel.makeKeyAndOrderFront(nil) - } - - static func openConfigurationView() { - let view = ConfigurationView() - let controller = NSHostingController(rootView: view) - - let window = NSWindow( - contentRect: .zero, - styleMask: [ - .closable, - .miniaturizable, - .titled, - .resizable - ], - backing: .buffered, - defer: false) - window.contentViewController = controller - window.toolbar = { - let toolbar = NSToolbar(identifier: "main") - let toolbarDelegate = ToolbarDelegate() - toolbar.delegate = toolbarDelegate - return toolbar - }() - window.toolbarStyle = .unified - window.center() - window.makeKeyAndOrderFront(nil) - } -} diff --git a/ChatGPTForXcodeEditorExtension/BaseCommand.swift b/ChatGPTForXcodeEditorExtension/BaseCommand.swift index 1fd3652..2ac7f5c 100644 --- a/ChatGPTForXcodeEditorExtension/BaseCommand.swift +++ b/ChatGPTForXcodeEditorExtension/BaseCommand.swift @@ -72,9 +72,13 @@ class BaseCommand: NSObject, XCSourceEditorCommand { let comments = [markerComment, reviewComment] let result = comments.joined(separator: "\n") buffer.lines.insert(result, at: selection.start.line) - if let url = URL(string: "chat-gpt-for-xcode://") { - NSWorkspace.shared.open(url) + + let encodedResult = result.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "" + if let url = URL(string: "chat-gpt-for-xcode://chat?\(encodedResult)") { + print("###", url) + NSWorkspace.shared.open(url) } + completionHandler(nil) } catch { completionHandler(error) From b6a47955dc92cb4dcfbf77f2205fdffca4e77406 Mon Sep 17 00:00:00 2001 From: Shota Abe Date: Sat, 25 Mar 2023 10:21:20 +0900 Subject: [PATCH 3/6] =?UTF-8?q?=E3=83=95=E3=83=AD=E3=83=BC=E3=83=86?= =?UTF-8?q?=E3=82=A3=E3=83=B3=E3=82=B0=E3=83=91=E3=83=8D=E3=83=AB=E3=81=A7?= =?UTF-8?q?=E3=81=AF=E3=80=81=E5=8D=98=E7=B4=94=E3=81=AB=E5=9B=9E=E7=AD=94?= =?UTF-8?q?=E3=82=92=E8=A1=A8=E7=A4=BA=E3=81=99=E3=82=8B=E3=82=88=E3=81=86?= =?UTF-8?q?=E3=81=AB=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ChatGPTForXcodeEditorExtension/BaseCommand.swift | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ChatGPTForXcodeEditorExtension/BaseCommand.swift b/ChatGPTForXcodeEditorExtension/BaseCommand.swift index 2ac7f5c..8cc8dfc 100644 --- a/ChatGPTForXcodeEditorExtension/BaseCommand.swift +++ b/ChatGPTForXcodeEditorExtension/BaseCommand.swift @@ -73,9 +73,8 @@ class BaseCommand: NSObject, XCSourceEditorCommand { let result = comments.joined(separator: "\n") buffer.lines.insert(result, at: selection.start.line) - let encodedResult = result.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "" - if let url = URL(string: "chat-gpt-for-xcode://chat?\(encodedResult)") { - print("###", url) + let encodedComment = (messageResult.choices.first?.message.content ?? "").addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "" + if let url = URL(string: "chat-gpt-for-xcode://chat?\(encodedComment)") { NSWorkspace.shared.open(url) } From fe9e46ee5dc22397931866f1b362a25c30b49c21 Mon Sep 17 00:00:00 2001 From: Shota Abe Date: Sun, 26 Mar 2023 22:07:05 +0900 Subject: [PATCH 4/6] =?UTF-8?q?floatingWindowToggle=E3=82=92=E4=BD=9C?= =?UTF-8?q?=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ChatGPTForXcode/ChatGPTForXcodeApp.swift | 3 +-- ChatGPTForXcode/ConfigurationView.swift | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/ChatGPTForXcode/ChatGPTForXcodeApp.swift b/ChatGPTForXcode/ChatGPTForXcodeApp.swift index 1d31747..c06663a 100644 --- a/ChatGPTForXcode/ChatGPTForXcodeApp.swift +++ b/ChatGPTForXcode/ChatGPTForXcodeApp.swift @@ -35,13 +35,12 @@ class AppDelegate: NSObject, NSApplicationDelegate { let view = ConfigurationView() let controller = NSHostingController(rootView: view) - let window = NSWindow( + let window = NSPanel( contentRect: .zero, styleMask: [ .closable, .miniaturizable, .titled, - .resizable ], backing: .buffered, defer: false) diff --git a/ChatGPTForXcode/ConfigurationView.swift b/ChatGPTForXcode/ConfigurationView.swift index aeabe58..c9d464a 100644 --- a/ChatGPTForXcode/ConfigurationView.swift +++ b/ChatGPTForXcode/ConfigurationView.swift @@ -18,7 +18,7 @@ struct ConfigurationView: View { var body: some View { NavigationStack { - VStack(spacing: 10) { + VStack(alignment: .leading, spacing: 10) { headline("1. Obtain your API Key from OpenAI.") link() @@ -30,9 +30,14 @@ struct ConfigurationView: View { headline("3. Specify the output language setting.") languagePicker() + + Divider() + .padding(.vertical, 4) + + floatingWindowToggle() } .padding(.init(top: 25, leading: 25, bottom: 25, trailing: 28)) - .frame(width: 400, height: 230, alignment: .center) + .frame(width: 400, height: 300, alignment: .center) .onAppear { apiKey = apiKeyRepository.getAPIKey() selectedLanguage = languageRepository.getSelectedLanguage() @@ -87,6 +92,15 @@ extension ConfigurationView { options: [NSApplication.AboutPanelOptionKey(rawValue: "Copyright"): "© 2023 Avis Inc"] ) } + + private func floatingWindowToggle() -> some View { + Toggle(isOn: .constant(true)) { + Text("Present suggestions in Floating Window") + .font(.system(size: 14)) + .frame(maxWidth: .infinity, alignment: .leading) + } + .toggleStyle(.switch) + } } struct ConfigurationView_Previews: PreviewProvider { From 3579e2bf83ac5d9c1b281180c399a6ca204d7c4b Mon Sep 17 00:00:00 2001 From: Shota Abe Date: Sun, 26 Mar 2023 22:19:02 +0900 Subject: [PATCH 5/6] =?UTF-8?q?=E3=83=95=E3=83=AD=E3=83=BC=E3=83=86?= =?UTF-8?q?=E3=82=A3=E3=83=B3=E3=82=B0=E3=82=A6=E3=82=A3=E3=83=B3=E3=83=89?= =?UTF-8?q?=E3=82=A6=E3=81=A7=E8=A1=A8=E7=A4=BA=E3=81=99=E3=82=8B=E3=81=8B?= =?UTF-8?q?=E3=81=A9=E3=81=86=E3=81=8B=E3=82=92=E4=BF=9D=E5=AD=98=E5=8F=AF?= =?UTF-8?q?=E8=83=BD=E3=81=AB=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ChatGPTForXcode/ChatGPTForXcodeApp.swift | 25 +++++++++++++------ ChatGPTForXcode/ConfigurationView.swift | 8 +++--- .../DisplayInFloatingWindowRepository.swift | 23 +++++++++++++++++ 3 files changed, 46 insertions(+), 10 deletions(-) create mode 100644 Shared/Infrastructure/Repository/DisplayInFloatingWindowRepository.swift diff --git a/ChatGPTForXcode/ChatGPTForXcodeApp.swift b/ChatGPTForXcode/ChatGPTForXcodeApp.swift index c06663a..ed843bc 100644 --- a/ChatGPTForXcode/ChatGPTForXcodeApp.swift +++ b/ChatGPTForXcode/ChatGPTForXcodeApp.swift @@ -29,6 +29,24 @@ struct ChatGPTForXcodeApp: App { class AppDelegate: NSObject, NSApplicationDelegate { func applicationDidFinishLaunching(_ notification: Notification) { + openConfigurationView() + } + + func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool { + if !flag { + openConfigurationView() + } + return true + } + + func application(_ application: NSApplication, open urls: [URL]) { + print(urls) + if let url = urls.first { + openChatPanel(url: url) + } + } + + private func openConfigurationView() { if NSApplication.shared.windows.filter({$0.identifier == .init("configurationWindow")}).first != nil { return } @@ -52,13 +70,6 @@ class AppDelegate: NSObject, NSApplicationDelegate { window.makeKeyAndOrderFront(nil) } - func application(_ application: NSApplication, open urls: [URL]) { - print(urls) - if let url = urls.first { - openChatPanel(url: url) - } - } - let chatViewModel = ChatViewModel() private func openChatPanel(url: URL) { diff --git a/ChatGPTForXcode/ConfigurationView.swift b/ChatGPTForXcode/ConfigurationView.swift index c9d464a..f68cadf 100644 --- a/ChatGPTForXcode/ConfigurationView.swift +++ b/ChatGPTForXcode/ConfigurationView.swift @@ -9,12 +9,12 @@ import SwiftUI struct ConfigurationView: View { private let apiKeyRepository = APIKeyRepository() - private let languageRepository = LanguageRepository() + private let displayInFloatingWindowRepository = DisplayInFloatingWindowRepository() @State private var apiKey = "" - @State private var selectedLanguage = Language.english + @State private var displayInFloatingWindow = false var body: some View { NavigationStack { @@ -41,9 +41,11 @@ struct ConfigurationView: View { .onAppear { apiKey = apiKeyRepository.getAPIKey() selectedLanguage = languageRepository.getSelectedLanguage() + displayInFloatingWindow = displayInFloatingWindowRepository.get() } .onChange(of: apiKey, perform: apiKeyRepository.saveAPIKey(apiKey:)) .onChange(of: selectedLanguage, perform: languageRepository.saveSelectedLanguage(language:)) + .onChange(of: displayInFloatingWindow, perform: displayInFloatingWindowRepository.save) .navigationTitle("ChatGPT for Xcode") .toolbar { toolbarButton() @@ -94,7 +96,7 @@ extension ConfigurationView { } private func floatingWindowToggle() -> some View { - Toggle(isOn: .constant(true)) { + Toggle(isOn: $displayInFloatingWindow) { Text("Present suggestions in Floating Window") .font(.system(size: 14)) .frame(maxWidth: .infinity, alignment: .leading) diff --git a/Shared/Infrastructure/Repository/DisplayInFloatingWindowRepository.swift b/Shared/Infrastructure/Repository/DisplayInFloatingWindowRepository.swift new file mode 100644 index 0000000..72463c4 --- /dev/null +++ b/Shared/Infrastructure/Repository/DisplayInFloatingWindowRepository.swift @@ -0,0 +1,23 @@ +// +// DisplayInFloatingWindowRepository.swift +// ChatGPTForXcode +// +// Created by 安部翔太 on 2023/03/26. +// + +import Foundation + +public struct DisplayInFloatingWindowRepository { + private let key = "displayInFloatingWindow" + + private let userDefaults = UserDefaults(suiteName: "com.ChatGPTForXcode.UserDefaults") + + func get() -> Bool { + let bool = userDefaults?.bool(forKey: key) + return bool ?? false + } + + func save(_ bool: Bool) { + userDefaults?.set(bool, forKey: key) + } +} From c0f69be2ecb47d29326000d2c97dc3e6dce577e4 Mon Sep 17 00:00:00 2001 From: Shota Abe Date: Sun, 26 Mar 2023 22:25:19 +0900 Subject: [PATCH 6/6] =?UTF-8?q?=E3=83=95=E3=83=AD=E3=83=BC=E3=83=86?= =?UTF-8?q?=E3=82=A3=E3=83=B3=E3=82=B0=E3=82=A6=E3=82=A3=E3=83=B3=E3=83=89?= =?UTF-8?q?=E3=82=A6=E3=81=8B=E3=82=B3=E3=83=A1=E3=83=B3=E3=83=88=E3=81=AE?= =?UTF-8?q?=E3=81=A9=E3=81=A1=E3=82=89=E3=81=8B=E3=81=AB=E7=B5=90=E6=9E=9C?= =?UTF-8?q?=E3=81=8C=E8=A1=A8=E7=A4=BA=E3=81=95=E3=82=8C=E3=82=8B=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BaseCommand.swift | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/ChatGPTForXcodeEditorExtension/BaseCommand.swift b/ChatGPTForXcodeEditorExtension/BaseCommand.swift index 8cc8dfc..ee33f17 100644 --- a/ChatGPTForXcodeEditorExtension/BaseCommand.swift +++ b/ChatGPTForXcodeEditorExtension/BaseCommand.swift @@ -47,10 +47,14 @@ class BaseCommand: NSObject, XCSourceEditorCommand { let apiKeyRepository = APIKeyRepository() let languageRepository = LanguageRepository() + + let displayInFloatingWindowRepository = DisplayInFloatingWindowRepository() let authToken = apiKeyRepository.getAPIKey() let language = languageRepository.getSelectedLanguage() + + let displayInFloatingWindow = displayInFloatingWindowRepository.get() let content = prompt(code, language: language) @@ -62,20 +66,23 @@ class BaseCommand: NSObject, XCSourceEditorCommand { .init(role: .user, content: content) ] ) - let indentSpace = String(repeating: " ", count: indentCount) - let markerComment = "\(indentSpace)// MARK: \(commandType.rawValue)" - var reviewComment = messageResult.choices.first?.message.content ?? "" - reviewComment = reviewComment - .split(separator: "\n") - .map { "\(indentSpace)/// \($0)" } - .joined(separator: "\n") - let comments = [markerComment, reviewComment] - let result = comments.joined(separator: "\n") - buffer.lines.insert(result, at: selection.start.line) - let encodedComment = (messageResult.choices.first?.message.content ?? "").addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "" - if let url = URL(string: "chat-gpt-for-xcode://chat?\(encodedComment)") { - NSWorkspace.shared.open(url) + if displayInFloatingWindow { + let encodedComment = (messageResult.choices.first?.message.content ?? "").addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "" + if let url = URL(string: "chat-gpt-for-xcode://chat?\(encodedComment)") { + NSWorkspace.shared.open(url) + } + } else { + let indentSpace = String(repeating: " ", count: indentCount) + let markerComment = "\(indentSpace)// MARK: \(commandType.rawValue)" + var reviewComment = messageResult.choices.first?.message.content ?? "" + reviewComment = reviewComment + .split(separator: "\n") + .map { "\(indentSpace)/// \($0)" } + .joined(separator: "\n") + let comments = [markerComment, reviewComment] + let result = comments.joined(separator: "\n") + buffer.lines.insert(result, at: selection.start.line) } completionHandler(nil)