Skip to content

Commit b08f93b

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 b08f93b

File tree

5 files changed

+54
-9
lines changed

5 files changed

+54
-9
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/AppBundle/layout/refresh.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ private var activeRefreshTask: Task<(), any Error>? = nil
77
@MainActor
88
func scheduleRefreshSession(
99
_ event: RefreshSessionEvent,
10-
optimisticallyPreLayoutWorkspaces: Bool = false,
10+
optimisticallyPreLayoutWorkspaces: Bool = false
1111
) {
1212
activeRefreshTask?.cancel()
1313
activeRefreshTask = Task { @MainActor in
@@ -20,7 +20,7 @@ func scheduleRefreshSession(
2020
func runRefreshSessionBlocking(
2121
_ event: RefreshSessionEvent,
2222
layoutWorkspaces shouldLayoutWorkspaces: Bool = true,
23-
optimisticallyPreLayoutWorkspaces: Bool = false,
23+
optimisticallyPreLayoutWorkspaces: Bool = false
2424
) async throws {
2525
let state = signposter.beginInterval(#function, "event: \(event) axTaskLocalAppThreadToken: \(axTaskLocalAppThreadToken?.idForDebug)")
2626
defer { signposter.endInterval(#function, state) }

Sources/Common/cmdArgs/impl/SummonWorkspaceCmdArgs.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
private let actio = "<action>"
2+
13
public struct SummonWorkspaceCmdArgs: CmdArgs {
24
/*conforms*/ public var commonState: CmdArgsCommonState
35
public init(rawArgs: StrArrSlice) { self.commonState = .init(rawArgs) }
@@ -7,14 +9,33 @@ public struct SummonWorkspaceCmdArgs: CmdArgs {
79
help: summon_workspace_help_generated,
810
flags: [
911
"--fail-if-noop": trueBoolFlag(\.failIfNoop),
12+
"--when-visible": SubArgParser(\.rawWhenVisibleAction, upcastSubArgParserFun(parseWhenVisibleAction)),
1013
],
1114
posArgs: [newArgParser(\.target, parseWorkspaceName, mandatoryArgPlaceholder: "<workspace>")],
1215
)
1316

1417
public var target: Lateinit<WorkspaceName> = .uninitialized
1518
public var failIfNoop: Bool = false
19+
public var rawWhenVisibleAction: WhenVisible? = nil
20+
21+
public enum WhenVisible: String, CaseIterable, Equatable, Sendable {
22+
case focus = "focus"
23+
case swap = "swap"
24+
}
25+
}
26+
27+
public extension SummonWorkspaceCmdArgs {
28+
var whenVisible: WhenVisible { rawWhenVisibleAction ?? .focus }
1629
}
1730

1831
private func parseWorkspaceName(i: ArgParserInput) -> ParsedCliArgs<WorkspaceName> {
1932
.init(WorkspaceName.parse(i.arg), advanceBy: 1)
2033
}
34+
35+
private func parseWhenVisibleAction(i: SubArgParserInput) -> ParsedCliArgs<SummonWorkspaceCmdArgs.WhenVisible> {
36+
if let arg = i.nonFlagArgOrNil() {
37+
return .init(parseEnum(arg, SummonWorkspaceCmdArgs.WhenVisible.self), advanceBy: 1)
38+
} else {
39+
return .fail("\(actio) is mandatory", advanceBy: 0)
40+
}
41+
}

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)