diff --git a/Sources/AppBundle/command/impl/SummonWorkspaceCommand.swift b/Sources/AppBundle/command/impl/SummonWorkspaceCommand.swift index 62f986090..460468eab 100644 --- a/Sources/AppBundle/command/impl/SummonWorkspaceCommand.swift +++ b/Sources/AppBundle/command/impl/SummonWorkspaceCommand.swift @@ -7,17 +7,36 @@ struct SummonWorkspaceCommand: Command { func run(_ env: CmdEnv, _ io: CmdIo) -> Bool { 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 { if !args.failIfNoop { 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 ca2327c61..cd07300b1 100644 --- a/Sources/Common/cmdArgs/impl/SummonWorkspaceCmdArgs.swift +++ b/Sources/Common/cmdArgs/impl/SummonWorkspaceCmdArgs.swift @@ -7,14 +7,33 @@ public struct SummonWorkspaceCmdArgs: CmdArgs { help: summon_workspace_help_generated, flags: [ "--fail-if-noop": trueBoolFlag(\.failIfNoop), + "--when-visible": SubArgParser(\.rawWhenVisibleAction, upcastSubArgParserFun(parseWhenVisibleAction)), ], posArgs: [newArgParser(\.target, parseWorkspaceName, mandatoryArgPlaceholder: "")], ) public var target: Lateinit = .uninitialized public var failIfNoop: Bool = false + public var rawWhenVisibleAction: WhenVisible? = nil + + public enum WhenVisible: String, CaseIterable, Equatable, Sendable { + case focus = "focus" + case swap = "swap" + } +} + +extension SummonWorkspaceCmdArgs { + public var whenVisible: WhenVisible { rawWhenVisibleAction ?? .focus } } private func parseWorkspaceName(i: ArgParserInput) -> ParsedCliArgs { .init(WorkspaceName.parse(i.arg), advanceBy: 1) } + +private func parseWhenVisibleAction(i: SubArgParserInput) -> ParsedCliArgs { + if let arg = i.nonFlagArgOrNil() { + return .init(parseEnum(arg, SummonWorkspaceCmdArgs.WhenVisible.self), advanceBy: 1) + } else { + return .fail(" is mandatory", advanceBy: 0) + } +} diff --git a/Sources/Common/cmdHelpGenerated.swift b/Sources/Common/cmdHelpGenerated.swift index abc217d70..368f18279 100644 --- a/Sources/Common/cmdHelpGenerated.swift +++ b/Sources/Common/cmdHelpGenerated.swift @@ -130,7 +130,7 @@ let split_help_generated = """ USAGE: split [-h|--help] [--window-id ] (horizontal|vertical|opposite) """ let summon_workspace_help_generated = """ - USAGE: summon-workspace [-h|--help] [--fail-if-noop] + USAGE: summon-workspace [-h|--help] [--fail-if-noop] [--when-visible (focus|swap)] """ let swap_help_generated = """ USAGE: swap [-h|--help] [--window-id ] [--swap-focus] diff --git a/docs/aerospace-summon-workspace.adoc b/docs/aerospace-summon-workspace.adoc index 331e720c8..d4d9776df 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 is 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[]