I'm developing a Swift application for macOS. I would like it to be able to interact with the user's shortcuts (block programs in the Shortcuts application, fig. 1). But I can't locate them...
Do you know where they are located and how I could display them in a picker (fig. 2) so that they can be selected by the user in the app?
Thanks in advance!
Fig. 1
Fig. 2
You can get the shortcuts' names using the shortcuts list
command. You can run this in Swift using a Process
. Here is a simple example:
struct ContentView: View {
@State var shortcuts = [ShortcutInfo]()
@State var selection = ""
var body: some View {
Picker("Pick a shortcut", selection: $selection) {
ForEach(shortcuts) {
Text($0.name)
}
}
.task {
let shortcuts = (try? await loadShortcutNames()) ?? []
self.shortcuts = shortcuts
selection = shortcuts.first?.id ?? ""
}
// use "shortcuts run" to run the shortcut
// there additional options to specify input
// see "shortcuts help run" for more info
Button("Run") {
let process = Process()
process.executableURL = URL(filePath: "/usr/bin/shortcuts")
process.arguments = ["run", selection]
try? process.run()
}
}
}
struct ShortcutInfo: Identifiable {
let id: String
let name: String
}
func loadShortcutNames() async throws -> [ShortcutInfo] {
let process = Process()
process.executableURL = URL(filePath: "/usr/bin/shortcuts")
// also get the UUID of the shortcut so that ShortcutInfo can be Identifiable
process.arguments = ["list", "--show-identifiers"]
let pipe = Pipe()
process.standardOutput = pipe
return try await withTaskCancellationHandler {
try process.run()
return try await pipe.fileHandleForReading.bytes.lines.compactMap { line in
// parse the shortcut name and ID
guard let (_, name, id) = line.wholeMatch(of: /(.*) \(([A-Z0-9-]*)\)/)?.output else {
return nil
}
return ShortcutInfo(id: String(id), name: String(name))
}.reduce(into: []) { $0.append($1) }
} onCancel: {
process.terminate()
}
}
For the icon and background color of the shortcuts though, they are stored in ~/Library/Shortcuts/Shortcuts.sqlite. You would need a SQLite client to read the database, and reverse-engineer the data. This would be quite fragile, as the database schema could very well change in future versions of macOS, so I wouldn't recommend that.
Hopefully there will be a proper API for accessing Shortcuts in the future.