-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Expand file tree
/
Copy pathShowMessageRequestHandler.swift
More file actions
118 lines (97 loc) · 4.1 KB
/
ShowMessageRequestHandler.swift
File metadata and controls
118 lines (97 loc) · 4.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import JSONRPC
import Foundation
import Combine
import Logger
import AppKit
import LanguageServerProtocol
import UserNotifications
public protocol ShowMessageRequestHandler {
func handleShowMessageRequest(
_ request: ShowMessageRequest,
callback: @escaping @Sendable (Result<MessageActionItem?, JSONRPCResponseError<JSONValue>>) async -> Void
)
}
public final class ShowMessageRequestHandlerImpl: NSObject, ShowMessageRequestHandler, UNUserNotificationCenterDelegate {
public static let shared = ShowMessageRequestHandlerImpl()
private var isNotificationSetup = false
private override init() {
super.init()
}
@MainActor
private func setupNotificationCenterIfNeeded() async {
guard !isNotificationSetup else { return }
guard Bundle.main.bundleIdentifier != nil else {
// Skip notification setup in test environment
return
}
isNotificationSetup = true
UNUserNotificationCenter.current().delegate = self
_ = try? await UNUserNotificationCenter.current()
.requestAuthorization(options: [.alert, .sound])
}
public func handleShowMessageRequest(
_ request: ShowMessageRequest,
callback: @escaping @Sendable (Result<MessageActionItem?, JSONRPCResponseError<JSONValue>>) async -> Void
) {
guard let params = request.params else { return }
Logger.gitHubCopilot.debug("Received Show Message Request: \(params)")
Task { @MainActor in
await setupNotificationCenterIfNeeded()
let actionCount = params.actions?.count ?? 0
// Use notification for messages with no action, alert for messages with actions
if actionCount == 0 {
await showMessageRequestNotification(params)
await callback(.success(nil))
} else {
let selectedAction = showMessageRequestAlert(params)
await callback(.success(selectedAction))
}
}
}
@MainActor
func showMessageRequestNotification(_ params: ShowMessageRequestParams) async {
let content = UNMutableNotificationContent()
content.title = "GitHub Copilot for Xcode"
content.body = params.message
content.sound = .default
let request = UNNotificationRequest(
identifier: UUID().uuidString,
content: content,
trigger: nil
)
do {
try await UNUserNotificationCenter.current().add(request)
} catch {
Logger.gitHubCopilot.error("Failed to show notification: \(error)")
}
}
@MainActor
func showMessageRequestAlert(_ params: ShowMessageRequestParams) -> MessageActionItem? {
let alert = NSAlert()
alert.messageText = "GitHub Copilot"
alert.informativeText = params.message
alert.alertStyle = params.type == .info ? .informational : .warning
let actions = params.actions ?? []
for item in actions {
alert.addButton(withTitle: item.title)
}
let response = alert.runModal()
// Map the button response to the corresponding action
// .alertFirstButtonReturn = 1000, .alertSecondButtonReturn = 1001, etc.
let buttonIndex = response.rawValue - NSApplication.ModalResponse.alertFirstButtonReturn.rawValue
guard buttonIndex >= 0 && buttonIndex < actions.count else {
return nil
}
return actions[buttonIndex]
}
// MARK: - UNUserNotificationCenterDelegate
// This method is called when a notification is delivered while the app is in the foreground
public func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
) {
// Show the notification banner even when app is in foreground
completionHandler([.banner, .list, .badge, .sound])
}
}