Created
April 29, 2026 16:08
-
-
Save xmollv/df94f2bef40c1e98fb2efc177727aae5 to your computer and use it in GitHub Desktop.
concurrency.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import SafariServices | |
| // TODO: Remove these conformances if Apple ships their own. | |
| extension SFSafariWindow: @retroactive @unchecked Sendable {} | |
| extension SFSafariPage: @retroactive @unchecked Sendable {} | |
| class SafariExtensionHandler: SFSafariExtensionHandler { | |
| // MARK: Toolbar | |
| override func validateToolbarItem(in window: SFSafariWindow, validationHandler: @escaping (Bool, String) -> Void) { | |
| nonisolated(unsafe) let handler = validationHandler | |
| Task { @MainActor in | |
| let url = await window.getURL() | |
| handler(url != nil, "") | |
| } | |
| } | |
| override func toolbarItemClicked(in window: SFSafariWindow) { | |
| Task { @MainActor in | |
| guard let url = await window.getURL() else { return } | |
| Self.handle(url: url) | |
| } | |
| } | |
| // MARK: Context menu | |
| override func contextMenuItemSelected(withCommand command: String, in page: SFSafariPage, userInfo: [String : Any]? = nil) { | |
| guard command == "io.xmollv.abyss.safari.contextmenu" else { return } | |
| if let userInfo, | |
| let link = userInfo["link"] as? String, | |
| let url = URL(string: link), | |
| url.scheme == "http" || url.scheme == "https" { | |
| Task { @MainActor in | |
| Self.handle(url: url) | |
| } | |
| } else { | |
| Task { @MainActor in | |
| guard let properties = await page.properties(), let url = properties.url else { return } | |
| Self.handle(url: url) | |
| } | |
| } | |
| } | |
| // MARK: Private helpers | |
| @MainActor | |
| private static func handle(url: URL) { | |
| guard let urlToOpen = URL(string: "later://x-callback-url/add?url=\(url.absoluteString)") else { return } | |
| NSWorkspace.shared.open(urlToOpen) | |
| } | |
| } | |
| private extension SFSafariWindow { | |
| func getURL() async -> URL? { | |
| guard let activeTab = await activeTab() else { return nil } | |
| guard let page = await activeTab.activePage() else { return nil } | |
| guard let properties = await page.properties() else { return nil } | |
| return properties.url | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
you should be able to remove those to retroactives and instead do:
This is only marginally-better, though. Ultimately, the problem is that
SFSafariExtensionHandlerisn't correctly annotated. So, we'd have to do pretty deep investigations into how it actually works here. Needing to subclass makes it particularly hard. But I would not be surprised to learn that it is actually a MainActor type. And if that's the case, this will become easy to fix later on.