-
-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathOpenURLSwapTabsPlugin.swift
100 lines (89 loc) · 4.16 KB
/
OpenURLSwapTabsPlugin.swift
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
import Apps
import AXEssibility
import Windows
import Cocoa
final class OpenURLSwapTabsPlugin {
enum OpenURLSwapToPluginError: Error {
case failedToCreate
case failedToCompile
case failedToRun
case couldNotFindOpenUrl
}
private let commandRunner: ScriptCommandRunner
init(_ commandRunner: ScriptCommandRunner) {
self.commandRunner = commandRunner
}
/// This function executes the open command, which opens a URL in a specific application.
/// If the target application is already running, it uses accessibility services to find and activate the window/tab with the matching URL. If accessibility services fail, it will run an AppleScript as the fallback to switch to the correct tab.
/// If the target application is not running, it opens the URL directly.
/// - Parameters:
/// - command: The open command to execute.
/// - Throws: An error if the URL cannot be opened.
func execute(_ path: String, appName: String,
appPath: String?, bundleIdentifier: String?,
checkCancellation: Bool) async throws {
// Get the bundle identifier of the target application, default to Safari if not provided
let bundleIdentifier = bundleIdentifier ?? "com.apple.Safari"
// Check if the target application is already running
if let runningApplication = NSWorkspace.shared.runningApplications
.first(where: { $0.bundleIdentifier == bundleIdentifier }) {
let axApp = AppAccessibilityElement(runningApplication.processIdentifier)
let windows = try axApp.windows()
// Flag to track if the URL was successfully opened using accessibility services
var success: Bool = false
for window in windows {
// Find the URL attribute of the web area in the window that matches the command path
if let url: URL = window.findAttribute(.url, of: "AXWebArea"),
url.absoluteString.contains(path) {
window.performAction(.raise)
runningApplication.activate(options: .activateIgnoringOtherApps)
success = true
break
}
}
if !success {
// Create an AppleScript to search for the URL in tabs
//
// This AppleScript code opens a specific URL in a specific application by swapping tabs.
// It takes the path of the URL and the name of the application as input.
// It activates the application and checks the URL of every tab in every window.
// If it finds a tab with a URL that contains the desired URL, it sets that window as the active window and switches to the corresponding tab.
// If it successfully swaps the tab, it returns 0. Otherwise, it returns -1.
let source = """
property matchingURL : "\(path)"
tell application "\(appName)"
activate
set theURLs to (get URL of every tab of every window)
repeat with x from 1 to length of theURLs
set tmp to item x of theURLs
repeat with y from 1 to length of tmp
if item y of tmp contains matchingURL then
set the index of window x to 1
tell window 1
if index of current tab is not y then set current tab to tab y
return 0
end tell
end if
end repeat
end repeat
return -1
end tell
"""
let scriptCommand = ScriptCommand(name: UUID().uuidString, kind: .appleScript, source: .inline(source), notification: nil)
// Run the script command and check the result
if try await commandRunner.run(scriptCommand, environment: [:], checkCancellation: checkCancellation) == "-1" {
throw OpenURLSwapToPluginError.couldNotFindOpenUrl
}
}
} else if let url = URL(string: path) {
// If the target application is not running, open the URL directly
let configuration = NSWorkspace.OpenConfiguration()
if let appPath {
try await NSWorkspace.shared.open([url], withApplicationAt: URL(filePath: appPath),
configuration: configuration)
} else {
NSWorkspace.shared.open(url)
}
}
}
}