diff --git a/LocalPackage/Sources/Common/cmdArgs/noCmdArgs.swift b/LocalPackage/Sources/Common/cmdArgs/noCmdArgs.swift index 8fa0391e..44e05675 100644 --- a/LocalPackage/Sources/Common/cmdArgs/noCmdArgs.swift +++ b/LocalPackage/Sources/Common/cmdArgs/noCmdArgs.swift @@ -22,10 +22,6 @@ public struct WorkspaceBackAndForthCmdArgs: RawCmdArgs, CmdArgs { public init() {} public static let parser: CmdParser = noArgsParser(.workspaceBackAndForth, allowInConfig: true) } -public struct ListAppsCmdArgs: RawCmdArgs, CmdArgs { - public init() {} - public static let parser: CmdParser = noArgsParser(.listApps, allowInConfig: false) -} public struct ServerVersionInternalCommandCmdArgs: RawCmdArgs, CmdArgs { public init() {} public static let parser: CmdParser = noArgsParser(.serverVersionInternalCommand, allowInConfig: false) diff --git a/LocalPackage/Sources/Common/cmdArgs/parseCmdArgs.swift b/LocalPackage/Sources/Common/cmdArgs/parseCmdArgs.swift index da4ea4ed..22864044 100644 --- a/LocalPackage/Sources/Common/cmdArgs/parseCmdArgs.swift +++ b/LocalPackage/Sources/Common/cmdArgs/parseCmdArgs.swift @@ -39,7 +39,7 @@ private func initSubcommands() -> [String: any SubCommandParserProtocol] { case .layout: result[kind.rawValue] = SubCommandParser(parseLayoutCmdArgs) case .listApps: - result[kind.rawValue] = noArgsSubCommandParser(ListAppsCmdArgs()) + result[kind.rawValue] = SubCommandParser(parseListAppsCmdArgs) case .listMonitors: result[kind.rawValue] = SubCommandParser(parseListMonitorsCmdArgs) case .listWindows: diff --git a/LocalPackage/Sources/Common/cmdArgs/query/ListAppsCmdArgs.swift b/LocalPackage/Sources/Common/cmdArgs/query/ListAppsCmdArgs.swift new file mode 100644 index 00000000..b819aafc --- /dev/null +++ b/LocalPackage/Sources/Common/cmdArgs/query/ListAppsCmdArgs.swift @@ -0,0 +1,24 @@ +public struct ListAppsCmdArgs: RawCmdArgs, CmdArgs { + public init() {} + public static let parser: CmdParser = cmdParser( + kind: .listApps, + allowInConfig: false, + help: """ + USAGE: list-apps [-h|--help] [--macos-hidden [no]] + + OPTIONS: + -h, --help Print help + --macos-hidden [no] Filter results to only print (not) hidden applications + """, + options: [ + "--macos-hidden": boolFlag(\.macosHidden), + ], + arguments: [] + ) + + public var macosHidden: Bool? +} + +public func parseListAppsCmdArgs(_ args: [String]) -> ParsedCmd { + parseRawCmdArgs(ListAppsCmdArgs(), args) +} diff --git a/LocalPackage/Sources/Common/cmdArgs/query/ListWindowsCmdArgs.swift b/LocalPackage/Sources/Common/cmdArgs/query/ListWindowsCmdArgs.swift index a0ef41af..bad82970 100644 --- a/LocalPackage/Sources/Common/cmdArgs/query/ListWindowsCmdArgs.swift +++ b/LocalPackage/Sources/Common/cmdArgs/query/ListWindowsCmdArgs.swift @@ -7,9 +7,9 @@ private struct RawListWindowsCmdArgs: RawCmdArgs, Equatable { allowInConfig: false, help: """ USAGE: list-windows [-h|--help] --workspace \(_workspaces) [--monitor \(_monitors)] - [--pid ] [--app-id ] + [--pid ] [--app-id ] [--macos-hidden-app [no]] OR: list-windows [-h|--help] --monitor \(_monitors) [--workspace \(_workspaces)] - [--pid ] [--app-id ] + [--pid ] [--app-id ] [--macos-hidden-app [no]] OR: list-windows [-h|--help] --all OR: list-windows [-h|--help] --focused @@ -21,6 +21,7 @@ private struct RawListWindowsCmdArgs: RawCmdArgs, Equatable { --monitor \(_monitors) Filter results to only print the windows that are attached to specified monitors --pid Filter results to only print windows that belong to the Application with specified --app-id Filter results to only print windows that belong to the Application with specified Bundle ID + --macos-hidden-app [no] Filter results to only print windows that belong to (not) hidden applications """, options: [ "--focused": trueBoolFlag(\.focused), @@ -29,6 +30,7 @@ private struct RawListWindowsCmdArgs: RawCmdArgs, Equatable { "--monitor": ArgParser(\.manual.monitors, parseMonitorIds), "--workspace": ArgParser(\.manual.workspaces, parseWorkspaces), "--pid": singleValueOption(\.manual.pidFilter, "", Int32.init), + "--macos-hidden-app": boolFlag(\.manual.macosHiddenApp), "--app-id": singleValueOption(\.manual.appIdFilter, "", { $0 }) ], arguments: [] @@ -68,6 +70,7 @@ public enum ListWindowsCmdArgs: CmdArgs { public var workspaces: [WorkspaceFilter] = [] public var pidFilter: Int32? public var appIdFilter: String? + public var macosHiddenApp: Bool? } } diff --git a/docs/aerospace-list-apps.adoc b/docs/aerospace-list-apps.adoc index 5d7224c2..18127dd5 100644 --- a/docs/aerospace-list-apps.adoc +++ b/docs/aerospace-list-apps.adoc @@ -7,7 +7,7 @@ include::util/man-attributes.adoc[] == Synopsis // tag::synopsis[] -list-apps [-h|--help] +list-apps [-h|--help] [--macos-hidden [no]] // end::synopsis[] == Description @@ -42,4 +42,8 @@ include::util/conditional-options-header.adoc[] -h, --help:: Print help +--macos-hidden [no]:: +Filter results to only print hidden applications. +`[no]` inverts the condition + include::util/man-footer.adoc[] diff --git a/docs/aerospace-list-windows.adoc b/docs/aerospace-list-windows.adoc index 48531f7c..c326ca8e 100644 --- a/docs/aerospace-list-windows.adoc +++ b/docs/aerospace-list-windows.adoc @@ -9,9 +9,9 @@ include::util/man-attributes.adoc[] [verse] // tag::synopsis[] list-windows [-h|--help] --workspace ... [--monitor ...] - [--pid ] [--app-id ] + [--pid ] [--app-id ] [--macos-hidden-app [no]] list-windows [-h|--help] --monitor ... [--workspace ...] - [--pid ] [--app-id ] + [--pid ] [--app-id ] [--macos-hidden-app [no]] list-windows [-h|--help] --all list-windows [-h|--help] --focused @@ -65,6 +65,10 @@ include::util/monitor-option.adoc[] --pid :: Filter results to only print windows that belong to the Application with specified `` --app-id :: Filter results to only print windows that belong to the Application with specified Bundle ID +--macos-hidden-app [no]:: +Filter results to only print windows that belong to hidden applications. +`[no]` inverts the condition + // end::body[] include::util/man-footer.adoc[] diff --git a/src/command/parseCommand.swift b/src/command/parseCommand.swift index e5727aea..7f61cf62 100644 --- a/src/command/parseCommand.swift +++ b/src/command/parseCommand.swift @@ -30,7 +30,7 @@ extension CmdArgs { case .layout: command = LayoutCommand(args: self as! LayoutCmdArgs) case .listApps: - command = ListAppsCommand() + command = ListAppsCommand(args: self as! ListAppsCmdArgs) case .listMonitors: command = ListMonitorsCommand(args: self as! ListMonitorsCmdArgs) case .listWindows: diff --git a/src/command/query/ListAppsCommand.swift b/src/command/query/ListAppsCommand.swift index b812ac81..e5fc7deb 100644 --- a/src/command/query/ListAppsCommand.swift +++ b/src/command/query/ListAppsCommand.swift @@ -1,11 +1,15 @@ import Common struct ListAppsCommand: Command { - let args = ListAppsCmdArgs() + let args: ListAppsCmdArgs func _run(_ state: CommandMutableState, stdin: String) -> Bool { check(Thread.current.isMainThread) - state.stdout += apps + var result = apps + if let hidden = args.macosHidden { + result = result.filter { $0.asMacApp().nsApp.isHidden == hidden } + } + state.stdout += result .map { app in let pid = String(app.pid) let appId = app.id ?? "NULL-APP-ID" diff --git a/src/command/query/ListWindowsCommand.swift b/src/command/query/ListWindowsCommand.swift index 927d9ccd..a9fc8b72 100644 --- a/src/command/query/ListWindowsCommand.swift +++ b/src/command/query/ListWindowsCommand.swift @@ -29,6 +29,9 @@ struct ListWindowsCommand: Command { if let pid = manual.pidFilter { windows = windows.filter { $0.app.pid == pid } } + if let macosHiddenApp = manual.macosHiddenApp { + windows = windows.filter { $0.macAppUnsafe.nsApp.isHidden == macosHiddenApp } + } if let appId = manual.appIdFilter { windows = windows.filter { $0.app.id == appId } } diff --git a/src/tree/AbstractApp.swift b/src/tree/AbstractApp.swift index 9e22c930..b38ad71d 100644 --- a/src/tree/AbstractApp.swift +++ b/src/tree/AbstractApp.swift @@ -27,3 +27,11 @@ class AbstractApp: Hashable { var name: String? { nil } func detectNewWindowsAndGetAll(startup: Bool) -> [Window] { error("Not implemented") } } + +extension AbstractApp { + func asMacApp() -> MacApp { self as! MacApp } +} + +extension Window { + var macAppUnsafe: MacApp { app.asMacApp() } +}