Skip to content

Commit 9cf0158

Browse files
committed
Merge branch 'pr/3' #3
2 parents 25218ea + a86ee36 commit 9cf0158

File tree

7 files changed

+66
-77
lines changed

7 files changed

+66
-77
lines changed

Sources/utiluti/AppCommands.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import ArgumentParser
1010
import UniformTypeIdentifiers
1111
import AppKit // for NSWorkspace
1212

13-
struct AppCommands: ParsableCommand {
13+
struct AppCommands: AsyncParsableCommand {
1414
static let configuration = CommandConfiguration(
1515
commandName: "app",
1616
abstract: "list uniform types identifiers and url schemes associated with an app",
@@ -20,7 +20,7 @@ struct AppCommands: ParsableCommand {
2020
]
2121
)
2222

23-
struct Types: ParsableCommand {
23+
struct Types: AsyncParsableCommand {
2424
static let configuration
2525
= CommandConfiguration(abstract: "List the uniform type identifiers this app can open")
2626

@@ -31,7 +31,7 @@ struct AppCommands: ParsableCommand {
3131
help: "show more information")
3232
var verbose: Bool = false
3333

34-
func run() {
34+
func run() async {
3535
guard
3636
let appURL = NSWorkspace.shared.urlForApplication(withBundleIdentifier: appID),
3737
let appBundle = Bundle(url: appURL),
@@ -82,7 +82,7 @@ struct AppCommands: ParsableCommand {
8282
}
8383
}
8484

85-
struct Schemes: ParsableCommand {
85+
struct Schemes: AsyncParsableCommand {
8686
static let configuration
8787
= CommandConfiguration(abstract: "List the urls schemes this app can open")
8888

@@ -93,7 +93,7 @@ struct AppCommands: ParsableCommand {
9393
help: "show more information")
9494
var verbose: Bool = false
9595

96-
func run() {
96+
func run() async {
9797
guard
9898
let appURL = NSWorkspace.shared.urlForApplication(withBundleIdentifier: appID),
9999
let appBundle = Bundle(url: appURL),

Sources/utiluti/FileCommands.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import ArgumentParser
1212
import UniformTypeIdentifiers
1313
import AppKit // for NSWorkspace
1414

15-
struct FileCommands: ParsableCommand {
15+
struct FileCommands: AsyncParsableCommand {
1616

1717
static var subCommands: [ParsableCommand.Type] {
1818
if #available(macOS 12.0, *) {
@@ -28,21 +28,21 @@ struct FileCommands: ParsableCommand {
2828
subcommands: subCommands
2929
)
3030

31-
struct GetUTI: ParsableCommand {
31+
struct GetUTI: AsyncParsableCommand {
3232
static let configuration
3333
= CommandConfiguration(abstract: "get the uniform type identifier of a file")
3434

3535
@Argument(help:ArgumentHelp("file path", valueName: "path"))
3636
var path: String
3737

38-
func run() {
38+
func run() async {
3939
let url = URL(fileURLWithPath: path)
4040
let typeIdentifier = try? url.resourceValues(forKeys: [.typeIdentifierKey]).typeIdentifier
4141
print(typeIdentifier ?? "<unknown>")
4242
}
4343
}
4444

45-
struct App: ParsableCommand {
45+
struct App: AsyncParsableCommand {
4646
static let configuration
4747
= CommandConfiguration(abstract: "get the app that will open this file")
4848

@@ -54,7 +54,7 @@ struct FileCommands: ParsableCommand {
5454
valueName: "bundleID"))
5555
var bundleID = false
5656

57-
func run() {
57+
func run() async {
5858
let url = URL(fileURLWithPath: path)
5959
if let app = NSWorkspace.shared.urlForApplication(toOpen: url) {
6060
if bundleID {
@@ -73,7 +73,7 @@ struct FileCommands: ParsableCommand {
7373
}
7474

7575
@available(macOS 12, *)
76-
struct ListApps: ParsableCommand {
76+
struct ListApps: AsyncParsableCommand {
7777
static let configuration
7878
= CommandConfiguration(abstract: "get all app that can open this file")
7979

@@ -85,7 +85,7 @@ struct FileCommands: ParsableCommand {
8585
valueName: "bundleID"))
8686
var bundleID = false
8787

88-
func run() {
88+
func run() async {
8989
let url = URL(fileURLWithPath: path)
9090
let apps = NSWorkspace.shared.urlsForApplications(toOpen: url)
9191
for app in apps {

Sources/utiluti/GetUTI.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import Foundation
99
import ArgumentParser
1010
import UniformTypeIdentifiers
1111

12-
struct GetUTI: ParsableCommand {
12+
struct GetUTI: AsyncParsableCommand {
1313
static let configuration
1414
= CommandConfiguration(abstract: "Get the type identifier (UTI) for a file extension")
1515

@@ -19,7 +19,7 @@ struct GetUTI: ParsableCommand {
1919
@Flag(help: "show dynamic identifiers")
2020
var showDynamic = false
2121

22-
func run() {
22+
func run() async {
2323
guard let utype = UTType(filenameExtension: fileExtension) else {
2424
Self.exit(withError: ExitCode(3))
2525
}

Sources/utiluti/LSKit.swift

Lines changed: 22 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -65,27 +65,21 @@ struct LSKit {
6565
- scheme: url scheme (excluding the `:` or `/`, e.g. `http`)
6666
- Returns: OSStatus (discardable)
6767
*/
68-
@discardableResult static func setDefaultApp(identifier: String, forScheme scheme: String) -> OSStatus {
68+
@discardableResult static func setDefaultApp(identifier: String, forScheme scheme: String) async -> OSStatus {
6969
if #available(macOS 12, *) {
7070
// print("running on macOS 12, using NSWorkspace")
71-
let ws = NSWorkspace.shared
72-
73-
// since the new NSWorkspace function is asynchronous we have to use semaphores here
74-
let semaphore = DispatchSemaphore(value: 0)
75-
var errCode: OSStatus = 0
76-
77-
guard let appURL = ws.urlForApplication(withBundleIdentifier: identifier) else { return 1 }
78-
ws.setDefaultApplication(at: appURL, toOpenURLsWithScheme: scheme) { err in
79-
// err is an NSError wrapped in a CocoaError
80-
if let err = err as? CocoaError {
81-
if let underlyingError = err.errorUserInfo["NSUnderlyingError"] as? NSError {
82-
errCode = OSStatus(clamping: underlyingError.code)
83-
}
71+
do {
72+
let ws = NSWorkspace.shared
73+
guard let appURL = ws.urlForApplication(withBundleIdentifier: identifier) else { return 1 }
74+
try await ws.setDefaultApplication(at: appURL, toOpenURLsWithScheme: scheme)
75+
return 0
76+
} catch {
77+
if let err = error as? CocoaError, let underlyingError = err.errorUserInfo["NSUnderlyingError"] as? NSError {
78+
return OSStatus(clamping: underlyingError.code)
79+
} else {
80+
return 1
8481
}
85-
semaphore.signal()
8682
}
87-
semaphore.wait()
88-
return errCode
8983
} else {
9084
return LSSetDefaultHandlerForURLScheme(scheme as CFString, identifier as CFString)
9185
}
@@ -147,31 +141,26 @@ struct LSKit {
147141
- forTypeIdentifier: uniform type identifier ( e.g. `public.html`)
148142
- Returns: OSStatus (discardable)
149143
*/
150-
@discardableResult static func setDefaultApp(identifier: String, forTypeIdentifier utidentifier: String) -> OSStatus {
144+
@discardableResult static func setDefaultApp(identifier: String, forTypeIdentifier utidentifier: String) async -> OSStatus {
151145
if #available(macOS 12, *) {
152146
// print("running on macOS 12, using NSWorkspace")
153147
guard let utype = UTType(utidentifier) else {
154148
return 1
155149
}
156-
157-
let ws = NSWorkspace.shared
158150

159-
// since the new NSWorkspace function is asynchronous we have to use semaphores here
160-
let semaphore = DispatchSemaphore(value: 0)
161-
var errCode: OSStatus = 0
162-
163-
guard let appURL = ws.urlForApplication(withBundleIdentifier: identifier) else { return 1 }
164-
ws.setDefaultApplication(at: appURL, toOpen: utype) { err in
151+
do {
152+
let ws = NSWorkspace.shared
153+
guard let appURL = ws.urlForApplication(withBundleIdentifier: identifier) else { return 1 }
154+
try await ws.setDefaultApplication(at: appURL, toOpen: utype)
155+
return 0
156+
} catch {
165157
// err is an NSError wrapped in a CocoaError
166-
if let err = err as? CocoaError {
167-
if let underlyingError = err.errorUserInfo["NSUnderlyingError"] as? NSError {
168-
errCode = OSStatus(clamping: underlyingError.code)
169-
}
158+
if let err = error as? CocoaError, let underlyingError = err.errorUserInfo["NSUnderlyingError"] as? NSError {
159+
return OSStatus(clamping: underlyingError.code)
160+
} else {
161+
return 1
170162
}
171-
semaphore.signal()
172163
}
173-
semaphore.wait()
174-
return errCode
175164
} else {
176165
return LSSetDefaultRoleHandlerForContentType(utidentifier as CFString, .all, identifier as CFString)
177166
}

Sources/utiluti/ManageCommand.swift

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import Foundation
99
import ArgumentParser
1010

11-
struct ManageCommand: ParsableCommand {
11+
struct ManageCommand: AsyncParsableCommand {
1212
static let configuration = CommandConfiguration(
1313
commandName: "manage",
1414
abstract: "read and apply settings from a managed preferences or a file"
@@ -47,15 +47,15 @@ struct ManageCommand: ParsableCommand {
4747
return prefs.dictionaryRepresentation(forKeys: Array(keys))
4848
}
4949

50-
func manageTypes(types: [String:Any]) throws {
50+
func manageTypes(types: [String:Any]) async throws {
5151
for (uti, value) in types {
5252
guard let bundleID = value as? String
5353
else {
5454
if verbose { print("skipping non-string value '\(value)' for \(uti)")}
5555
continue
5656
}
5757

58-
let result = LSKit.setDefaultApp(identifier: bundleID, forTypeIdentifier: uti)
58+
let result = await LSKit.setDefaultApp(identifier: bundleID, forTypeIdentifier: uti)
5959
if result == 0 {
6060
print("set \(bundleID) for \(uti)")
6161
} else {
@@ -64,15 +64,15 @@ struct ManageCommand: ParsableCommand {
6464
}
6565
}
6666

67-
func manageURLs(urls: [String:Any]) throws {
67+
func manageURLs(urls: [String:Any]) async throws {
6868
for (urlScheme, value) in urls {
6969
guard let bundleID = value as? String
7070
else {
7171
if verbose { print("skipping non-string value '\(value)' for \(urlScheme)")}
7272
continue
7373
}
7474

75-
let result = LSKit.setDefaultApp(identifier: bundleID, forScheme: urlScheme)
75+
let result = await LSKit.setDefaultApp(identifier: bundleID, forScheme: urlScheme)
7676

7777
if result == 0 {
7878
print("set \(bundleID) for \(urlScheme)")
@@ -82,24 +82,24 @@ struct ManageCommand: ParsableCommand {
8282
}
8383
}
8484

85-
func run() throws {
85+
func run() async throws {
8686
if typeFile == nil && urlFile == nil {
8787
// neither file path is set, read from defaults
8888
let types = try dictionary(fromDefaults: "com.scriptingosx.utiluti.type")
89-
try manageTypes(types: types)
89+
try await manageTypes(types: types)
9090

9191
let urls = try dictionary(fromDefaults: "com.scriptingosx.utiluti.url")
92-
try manageURLs(urls: urls)
92+
try await manageURLs(urls: urls)
9393
} else {
9494
// one or both of the file paths are set
9595
if let typeFile {
9696
let types = try dictionary(forFile: typeFile)
97-
try manageTypes(types: types)
97+
try await manageTypes(types: types)
9898
}
9999

100100
if let urlFile {
101101
let urls = try dictionary(forFile: urlFile)
102-
try manageURLs(urls: urls)
102+
try await manageURLs(urls: urls)
103103
}
104104
}
105105
}

Sources/utiluti/TypeCommands.swift

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import Foundation
99
import ArgumentParser
1010
import UniformTypeIdentifiers
1111

12-
struct TypeCommands: ParsableCommand {
12+
struct TypeCommands: AsyncParsableCommand {
1313

1414
static let configuration = CommandConfiguration(
1515
commandName: "type",
@@ -38,14 +38,14 @@ struct TypeCommands: ParsableCommand {
3838
var bundleID = false
3939
}
4040

41-
struct Get: ParsableCommand {
41+
struct Get: AsyncParsableCommand {
4242
static let configuration
4343
= CommandConfiguration(abstract: "Get the path to the default application.")
4444

4545
@OptionGroup var utidentifier: UTIdentifier
4646
@OptionGroup var bundleID: IdentifierFlag
4747

48-
func run() {
48+
func run() async {
4949
guard let appURL = LSKit.defaultAppURL(forTypeIdentifier: utidentifier.value) else {
5050
print("<no default app found>")
5151
return
@@ -61,14 +61,14 @@ struct TypeCommands: ParsableCommand {
6161
}
6262
}
6363

64-
struct List: ParsableCommand {
64+
struct List: AsyncParsableCommand {
6565
static let configuration
6666
= CommandConfiguration(abstract: "List all applications that can handle this type identifier.")
6767

6868
@OptionGroup var utidentifier: UTIdentifier
6969
@OptionGroup var bundleID: IdentifierFlag
7070

71-
func run() {
71+
func run() async {
7272
let appURLs = LSKit.appURLs(forTypeIdentifier: utidentifier.value)
7373

7474
for appURL in appURLs {
@@ -85,15 +85,15 @@ struct TypeCommands: ParsableCommand {
8585
}
8686
}
8787

88-
struct Set: ParsableCommand {
88+
struct Set: AsyncParsableCommand {
8989
static let configuration
9090
= CommandConfiguration(abstract: "Set the default app for this type identifier.")
9191

9292
@OptionGroup var utidentifier: UTIdentifier
9393
@Argument var identifier: String
9494

95-
func run() {
96-
let result = LSKit.setDefaultApp(identifier: identifier, forTypeIdentifier: utidentifier.value)
95+
func run() async {
96+
let result = await LSKit.setDefaultApp(identifier: identifier, forTypeIdentifier: utidentifier.value)
9797

9898
if result == 0 {
9999
print("set \(identifier) for \(utidentifier.value)")
@@ -104,13 +104,13 @@ struct TypeCommands: ParsableCommand {
104104
}
105105
}
106106

107-
struct FileExtensions: ParsableCommand {
107+
struct FileExtensions: AsyncParsableCommand {
108108
static let configuration
109109
= CommandConfiguration(abstract: "prints the file extensions for the given type identifier")
110110

111111
@OptionGroup var utidentifier: UTIdentifier
112112

113-
func run() {
113+
func run() async {
114114
guard let utype = UTType(utidentifier.value) else {
115115
print("<none>")
116116
TypeCommands.exit(withError: ExitCode(3))
@@ -121,13 +121,13 @@ struct TypeCommands: ParsableCommand {
121121
}
122122
}
123123

124-
struct Info: ParsableCommand {
124+
struct Info: AsyncParsableCommand {
125125
static let configuration
126126
= CommandConfiguration(abstract: "prints information for the given type identifier")
127127

128128
@OptionGroup var utidentifier: UTIdentifier
129129

130-
func run() {
130+
func run() async {
131131
guard let utype = UTType(utidentifier.value) else {
132132
print("<none>")
133133
TypeCommands.exit(withError: ExitCode(3))

0 commit comments

Comments
 (0)