@@ -3,13 +3,27 @@ import Dependencies
33import XcodeInspector
44
55public extension NSWorkspace {
6- static func activateThisApp( delay: TimeInterval = 0.5 ) {
6+ static func activateThisApp( delay: TimeInterval = 0.3 ) {
77 Task { @MainActor in
88 try await Task . sleep ( nanoseconds: UInt64 ( delay * 1_000_000_000 ) )
9- // NSApp.activate may fail.
10- NSRunningApplication (
11- processIdentifier: ProcessInfo . processInfo. processIdentifier
12- ) ? . activate ( )
9+
10+ // NSApp.activate may fail. And since macOS 14, it looks like the app needs other
11+ // apps to call `yieldActivationToApplication` to activate itself?
12+
13+ let activated = NSRunningApplication . current
14+ . activate ( options: [ . activateIgnoringOtherApps] )
15+
16+ if activated { return }
17+
18+ // Fallback solution
19+
20+ let appleScript = """
21+ tell application " System Events "
22+ set frontmost of the first process whose unix id is \
23+ \( ProcessInfo . processInfo. processIdentifier) to true
24+ end tell
25+ """
26+ try await runAppleScript ( appleScript)
1327 }
1428 }
1529
@@ -20,7 +34,7 @@ public extension NSWorkspace {
2034 app. runningApplication. activate ( )
2135 }
2236 }
23-
37+
2438 static func activatePreviousActiveXcode( delay: TimeInterval = 0.2 ) {
2539 Task { @MainActor in
2640 guard let app = XcodeInspector . shared. latestActiveXcode else { return }
@@ -52,10 +66,41 @@ public extension DependencyValues {
5266 get { self [ ActivatePreviousActiveAppDependencyKey . self] }
5367 set { self [ ActivatePreviousActiveAppDependencyKey . self] = newValue }
5468 }
55-
69+
5670 var activatePreviousActiveXcode : ( ) -> Void {
5771 get { self [ ActivatePreviousActiveXcodeDependencyKey . self] }
5872 set { self [ ActivatePreviousActiveXcodeDependencyKey . self] = newValue }
5973 }
6074}
6175
76+ @discardableResult
77+ func runAppleScript( _ appleScript: String ) async throws -> String {
78+ let task = Process ( )
79+ task. launchPath = " /usr/bin/osascript "
80+ task. arguments = [ " -e " , appleScript]
81+ let outpipe = Pipe ( )
82+ task. standardOutput = outpipe
83+ task. standardError = Pipe ( )
84+
85+ return try await withUnsafeThrowingContinuation { continuation in
86+ do {
87+ task. terminationHandler = { _ in
88+ do {
89+ if let data = try outpipe. fileHandleForReading. readToEnd ( ) ,
90+ let content = String ( data: data, encoding: . utf8)
91+ {
92+ continuation. resume ( returning: content)
93+ return
94+ }
95+ continuation. resume ( returning: " " )
96+ } catch {
97+ continuation. resume ( throwing: error)
98+ }
99+ }
100+ try task. run ( )
101+ } catch {
102+ continuation. resume ( throwing: error)
103+ }
104+ }
105+ }
106+
0 commit comments