diff --git a/Sources/AppBundle/command/impl/SummonWorkspaceCommand.swift b/Sources/AppBundle/command/impl/SummonWorkspaceCommand.swift index d2d66ac0..bd667e30 100644 --- a/Sources/AppBundle/command/impl/SummonWorkspaceCommand.swift +++ b/Sources/AppBundle/command/impl/SummonWorkspaceCommand.swift @@ -7,15 +7,36 @@ struct SummonWorkspaceCommand: Command { func run(_ env: CmdEnv, _ io: CmdIo) -> Bool { check(Thread.current.isMainThread) let workspace = Workspace.get(byName: args.target.val.raw) - let monitor = focus.workspace.workspaceMonitor - if monitor.activeWorkspace == workspace { + let focusedMonitor = focus.workspace.workspaceMonitor + + if focusedMonitor.activeWorkspace == workspace { io.err("Workspace '\(workspace.name)' is already visible on the focused monitor. Tip: use --fail-if-noop to exit with non-zero code") return !args.failIfNoop } - if monitor.setActiveWorkspace(workspace) { - return workspace.focusWorkspace() + + if !workspace.isVisible { + // then we just need to summon the workspace to the focused monitor + if focusedMonitor.setActiveWorkspace(workspace) { + return workspace.focusWorkspace() + } else { + return io.err("Can't move workspace '\(workspace.name)' to monitor '\(focusedMonitor.name)'. workspace-to-monitor-force-assignment doesn't allow it") + } } else { - return io.err("Can't move workspace '\(workspace.name)' to monitor '\(monitor.name)'. workspace-to-monitor-force-assignment doesn't allow it") + let otherMonitor = workspace.workspaceMonitor + let currentWorkspace = focusedMonitor.activeWorkspace + + switch args.whenVisible { + case .swap: + if otherMonitor.setActiveWorkspace(currentWorkspace) && focusedMonitor.setActiveWorkspace(workspace) { + return workspace.focusWorkspace() + } else { + return io.err("Can't swap workspaces due to monitor force assignment restrictions") + } + case .focus: + return workspace.focusWorkspace() + } + + } } } diff --git a/Sources/Common/cmdArgs/impl/SummonWorkspaceCmdArgs.swift b/Sources/Common/cmdArgs/impl/SummonWorkspaceCmdArgs.swift index 8feb2fe2..c3444a57 100644 --- a/Sources/Common/cmdArgs/impl/SummonWorkspaceCmdArgs.swift +++ b/Sources/Common/cmdArgs/impl/SummonWorkspaceCmdArgs.swift @@ -1,3 +1,5 @@ +private let actio = "" + public struct SummonWorkspaceCmdArgs: CmdArgs { public let rawArgs: EquatableNoop<[String]> public init(rawArgs: [String]) { self.rawArgs = .init(rawArgs) } @@ -7,6 +9,7 @@ public struct SummonWorkspaceCmdArgs: CmdArgs { help: summon_workspace_help_generated, options: [ "--fail-if-noop": trueBoolFlag(\.failIfNoop), + "--when-visible": ArgParser(\.rawWhenVisibleAction, upcastArgParserFun(parseWhenVisibleAction)), ], arguments: [newArgParser(\.target, parseWorkspaceName, mandatoryArgPlaceholder: "")] ) @@ -16,8 +19,26 @@ public struct SummonWorkspaceCmdArgs: CmdArgs { public var target: Lateinit = .uninitialized public var failIfNoop: Bool = false + public var rawWhenVisibleAction: WhenVisible? = nil + + public enum WhenVisible: String, CaseIterable, Equatable { + case focus = "focus" + case swap = "swap" + } +} + +public extension SummonWorkspaceCmdArgs { + var whenVisible: WhenVisible { rawWhenVisibleAction ?? .focus } } private func parseWorkspaceName(arg: String, nextArgs: inout [String]) -> Parsed { WorkspaceName.parse(arg) } + +private func parseWhenVisibleAction(arg: String, nextArgs: inout [String]) -> Parsed { + if let arg = nextArgs.nextNonFlagOrNil() { + return parseEnum(arg, SummonWorkspaceCmdArgs.WhenVisible.self) + } else { + return .failure("\(actio) is mandatory") + } +} diff --git a/docs/aerospace-summon-workspace.adoc b/docs/aerospace-summon-workspace.adoc index 67f7388d..ca6b3f82 100644 --- a/docs/aerospace-summon-workspace.adoc +++ b/docs/aerospace-summon-workspace.adoc @@ -9,7 +9,7 @@ include::util/man-attributes.adoc[] == Synopsis [verse] // tag::synopsis[] -aerospace summon-workspace [-h|--help] [--fail-if-noop] +aerospace summon-workspace [-h|--help] [--fail-if-noop] [--when-visible (focus|swap)] // end::synopsis[] @@ -30,6 +30,11 @@ include::./util/conditional-options-header.adoc[] -h, --help:: Print help --fail-if-noop:: Exit with non-zero exit code if the workspace already visible on the focused monitor. +--when-visible :: +Defines the behavior if the workspace is already visible on another monitor. +`` possible values: `(focus|swap)`. + +The default is: `focus` + // =========================================================== Arguments include::./util/conditional-arguments-header.adoc[]