Skip to content

Commit 06999b7

Browse files
lynaghkawwaiid
authored andcommitted
Add --when-visible (focus|swap) option to the summon-workspace command.
What should happen when the summoned workspace is visible on another monitor? This option introduces a choice to either: - `focus` the monitor on which the target workspace is already visible (the current behavior) - `swap` the workspaces between the monitors, so that the summoned workspace appears on the focused monitor. The default is `focus`, for backwards compatibility. Ref: #603
1 parent 18545c2 commit 06999b7

File tree

4 files changed

+50
-7
lines changed

4 files changed

+50
-7
lines changed

Sources/AppBundle/command/impl/SummonWorkspaceCommand.swift

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,36 @@ struct SummonWorkspaceCommand: Command {
77

88
func run(_ env: CmdEnv, _ io: CmdIo) -> Bool {
99
let workspace = Workspace.get(byName: args.target.val.raw)
10-
let monitor = focus.workspace.workspaceMonitor
11-
if monitor.activeWorkspace == workspace {
10+
let focusedMonitor = focus.workspace.workspaceMonitor
11+
12+
if focusedMonitor.activeWorkspace == workspace {
1213
if !args.failIfNoop {
1314
io.err("Workspace '\(workspace.name)' is already visible on the focused monitor. Tip: use --fail-if-noop to exit with non-zero code")
1415
}
1516
return !args.failIfNoop
1617
}
17-
if monitor.setActiveWorkspace(workspace) {
18-
return workspace.focusWorkspace()
18+
19+
if !workspace.isVisible {
20+
// then we just need to summon the workspace to the focused monitor
21+
if focusedMonitor.setActiveWorkspace(workspace) {
22+
return workspace.focusWorkspace()
23+
} else {
24+
return io.err("Can't move workspace '\(workspace.name)' to monitor '\(focusedMonitor.name)'. workspace-to-monitor-force-assignment doesn't allow it")
25+
}
1926
} else {
20-
return io.err("Can't move workspace '\(workspace.name)' to monitor '\(monitor.name)'. workspace-to-monitor-force-assignment doesn't allow it")
27+
let otherMonitor = workspace.workspaceMonitor
28+
let currentWorkspace = focusedMonitor.activeWorkspace
29+
30+
switch args.whenVisible {
31+
case .swap:
32+
if otherMonitor.setActiveWorkspace(currentWorkspace) && focusedMonitor.setActiveWorkspace(workspace) {
33+
return workspace.focusWorkspace()
34+
} else {
35+
return io.err("Can't swap workspaces due to monitor force assignment restrictions")
36+
}
37+
case .focus:
38+
return workspace.focusWorkspace()
39+
}
2140
}
2241
}
2342
}

Sources/Common/cmdArgs/impl/SummonWorkspaceCmdArgs.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,33 @@ public struct SummonWorkspaceCmdArgs: CmdArgs {
77
help: summon_workspace_help_generated,
88
flags: [
99
"--fail-if-noop": trueBoolFlag(\.failIfNoop),
10+
"--when-visible": SubArgParser(\.rawWhenVisibleAction, upcastSubArgParserFun(parseWhenVisibleAction)),
1011
],
1112
posArgs: [newArgParser(\.target, parseWorkspaceName, mandatoryArgPlaceholder: "<workspace>")],
1213
)
1314

1415
public var target: Lateinit<WorkspaceName> = .uninitialized
1516
public var failIfNoop: Bool = false
17+
public var rawWhenVisibleAction: WhenVisible? = nil
18+
19+
public enum WhenVisible: String, CaseIterable, Equatable, Sendable {
20+
case focus = "focus"
21+
case swap = "swap"
22+
}
23+
}
24+
25+
public extension SummonWorkspaceCmdArgs {
26+
var whenVisible: WhenVisible { rawWhenVisibleAction ?? .focus }
1627
}
1728

1829
private func parseWorkspaceName(i: ArgParserInput) -> ParsedCliArgs<WorkspaceName> {
1930
.init(WorkspaceName.parse(i.arg), advanceBy: 1)
2031
}
32+
33+
private func parseWhenVisibleAction(i: SubArgParserInput) -> ParsedCliArgs<SummonWorkspaceCmdArgs.WhenVisible> {
34+
if let arg = i.nonFlagArgOrNil() {
35+
return .init(parseEnum(arg, SummonWorkspaceCmdArgs.WhenVisible.self), advanceBy: 1)
36+
} else {
37+
return .fail("<action> is mandatory", advanceBy: 0)
38+
}
39+
}

Sources/Common/cmdHelpGenerated.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ let split_help_generated = """
130130
USAGE: split [-h|--help] [--window-id <window-id>] (horizontal|vertical|opposite)
131131
"""
132132
let summon_workspace_help_generated = """
133-
USAGE: summon-workspace [-h|--help] [--fail-if-noop] <workspace>
133+
USAGE: summon-workspace [-h|--help] [--fail-if-noop] [--when-visible (focus|swap)] <workspace>
134134
"""
135135
let swap_help_generated = """
136136
USAGE: swap [-h|--help] [--window-id <window-id>] [--swap-focus]

docs/aerospace-summon-workspace.adoc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ include::util/man-attributes.adoc[]
99
== Synopsis
1010
[verse]
1111
// tag::synopsis[]
12-
aerospace summon-workspace [-h|--help] [--fail-if-noop] <workspace>
12+
aerospace summon-workspace [-h|--help] [--fail-if-noop] [--when-visible (focus|swap)] <workspace>
1313

1414
// end::synopsis[]
1515

@@ -30,6 +30,11 @@ include::./util/conditional-options-header.adoc[]
3030
-h, --help:: Print help
3131
--fail-if-noop:: Exit with non-zero exit code if the workspace is already visible on the focused monitor.
3232

33+
--when-visible <action>::
34+
Defines the behavior if the workspace is already visible on another monitor.
35+
`<action>` possible values: `(focus|swap)`. +
36+
The default is: `focus`
37+
3338
// =========================================================== Arguments
3439
include::./util/conditional-arguments-header.adoc[]
3540

0 commit comments

Comments
 (0)