Skip to content

Commit 51cf4dd

Browse files
committed
added 'file app' and 'file set'
1 parent 52ca1a3 commit 51cf4dd

File tree

2 files changed

+93
-3
lines changed

2 files changed

+93
-3
lines changed

Sources/utiluti/FileCommands.swift

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,19 @@ import UniformTypeIdentifiers
1313
import AppKit // for NSWorkspace
1414

1515
struct FileCommands: ParsableCommand {
16+
17+
static var subCommands: [ParsableCommand.Type] {
18+
if #available(macOS 12.0, *) {
19+
return [ GetUTI.self, App.self, ListApps.self, Set.self ]
20+
} else {
21+
return [ GetUTI.self, App.self ]
22+
}
23+
}
24+
1625
static let configuration = CommandConfiguration(
1726
commandName: "file",
1827
abstract: "commands to manage specific files",
19-
subcommands: [ GetUTI.self ]
28+
subcommands: subCommands
2029
)
2130

2231
struct GetUTI: ParsableCommand {
@@ -32,5 +41,86 @@ struct FileCommands: ParsableCommand {
3241
print(typeIdentifier ?? "<unknown>")
3342
}
3443
}
44+
45+
struct App: ParsableCommand {
46+
static let configuration
47+
= CommandConfiguration(abstract: "get the app that will open this file")
48+
49+
@Argument(help:ArgumentHelp("file path", valueName: "path"))
50+
var path: String
51+
52+
@Flag(help: ArgumentHelp(
53+
"list bundle identifiers instead of paths",
54+
valueName: "bundleID"))
55+
var bundleID = false
56+
57+
func run() {
58+
let url = URL(fileURLWithPath: path)
59+
if let app = NSWorkspace.shared.urlForApplication(toOpen: url) {
60+
if bundleID {
61+
guard let appBundle = Bundle(url: app) else {
62+
Self.exit(withError: ExitCode(6))
63+
}
64+
print(appBundle.bundleIdentifier ?? "<no identifier>")
65+
} else {
66+
print(app.path)
67+
}
68+
} else {
69+
print("no app found")
70+
Self.exit(withError: ExitCode(9))
71+
}
72+
}
73+
}
74+
75+
@available(macOS 12, *)
76+
struct ListApps: ParsableCommand {
77+
static let configuration
78+
= CommandConfiguration(abstract: "get all app that can open this file")
79+
80+
@Argument(help:ArgumentHelp("file path", valueName: "path"))
81+
var path: String
82+
83+
@Flag(help: ArgumentHelp(
84+
"list bundle identifiers instead of paths",
85+
valueName: "bundleID"))
86+
var bundleID = false
87+
88+
func run() {
89+
let url = URL(fileURLWithPath: path)
90+
let apps = NSWorkspace.shared.urlsForApplications(toOpen: url)
91+
for app in apps {
92+
if bundleID {
93+
guard let appBundle = Bundle(url: app) else {
94+
Self.exit(withError: ExitCode(6))
95+
}
96+
print(appBundle.bundleIdentifier ?? "<no identifier>")
97+
} else {
98+
print(app.path)
99+
}
100+
}
101+
}
102+
}
103+
104+
@available(macOS 12, *)
105+
struct Set: AsyncParsableCommand {
106+
static let configuration
107+
= CommandConfiguration(abstract: "Set the default app for this specific file")
108+
109+
@Argument(help:ArgumentHelp("file path", valueName: "path"))
110+
var path: String
111+
112+
@Argument(help: "the bundle identifier for the new default app")
113+
var identifier: String
114+
115+
func run() async throws {
116+
let url = URL(fileURLWithPath: path)
117+
guard let appURL = NSWorkspace.shared.urlForApplication(withBundleIdentifier: identifier)
118+
else {
119+
Self.exit(withError: ExitCode(11))
120+
}
121+
try await NSWorkspace.shared.setDefaultApplication(at: appURL, toOpenFileAt: url)
122+
print("set \(identifier) for \(path)")
123+
}
124+
}
35125
}
36126

Sources/utiluti/utiluti.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ import Foundation
55
import ArgumentParser
66

77
@main
8-
struct UtilUTI: ParsableCommand {
8+
struct UtilUTI: AsyncParsableCommand {
99
static let subCommands: [ParsableCommand.Type] = [URLCommands.self, TypeCommands.self, GetUTI.self, AppCommands.self, FileCommands.self]
1010

1111
static let configuration = CommandConfiguration(
1212
commandName: "utiluti",
1313
abstract: "Read and set default URL scheme and file type handlers.",
14-
version: "1.1",
14+
version: "1.1dev",
1515
subcommands: subCommands
1616
)
1717
}

0 commit comments

Comments
 (0)