Skip to content

Commit

Permalink
Implement list-workspaces
Browse files Browse the repository at this point in the history
#16 WIP
  • Loading branch information
nikitabobko committed Dec 28, 2023
1 parent 3c01417 commit 37956db
Show file tree
Hide file tree
Showing 10 changed files with 141 additions and 2 deletions.
4 changes: 4 additions & 0 deletions AeroSpace.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
2E691C1E3F03B82F8507A435 /* MoveCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1376845BAB666880919B9AA2 /* MoveCommand.swift */; };
374CE35B85B941B8F584C113 /* FlattenWorkspaceTreeCommandTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53FDECECC773EBA30661EB8A /* FlattenWorkspaceTreeCommandTest.swift */; };
3774857EF024E97B7AA5DE78 /* MoveNodeToWorkspaceCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25AC44D0E9450867215FCBEC /* MoveNodeToWorkspaceCommand.swift */; };
3AFD7EE961B97F38C0914A0C /* ListWorkspacesCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E6478C499F3FB86C017D7BB /* ListWorkspacesCommand.swift */; };
3BD6FF4CC51532977DA0C05A /* AeroAny.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82476B9BEBAC00EB9E32256F /* AeroAny.swift */; };
42197B9C71A0CDDE65804A6A /* accessibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D31BF26EAFA96F675D2C14B /* accessibility.swift */; };
43E3628E37D2439B820FFC82 /* server.swift in Sources */ = {isa = PBXBuildFile; fileRef = 796713A1B3AEEBF4D0D180C7 /* server.swift */; };
Expand Down Expand Up @@ -158,6 +159,7 @@
9857501E54FC080D2A62DCE4 /* MoveCommandTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoveCommandTest.swift; sourceTree = "<group>"; };
99853C505D93E41F6531C324 /* CloseAllWindowsButCurrentCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloseAllWindowsButCurrentCommand.swift; sourceTree = "<group>"; };
9D31BF26EAFA96F675D2C14B /* accessibility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = accessibility.swift; sourceTree = "<group>"; };
9E6478C499F3FB86C017D7BB /* ListWorkspacesCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListWorkspacesCommand.swift; sourceTree = "<group>"; };
9ECC990B6C2D66D343216A12 /* FullscreenCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullscreenCommand.swift; sourceTree = "<group>"; };
9F6B8A501483ACBB62560101 /* TreeNodeEx.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TreeNodeEx.swift; sourceTree = "<group>"; };
A60709210745C60D64F82D53 /* TreeNodeKind.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TreeNodeKind.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -353,6 +355,7 @@
children = (
B0185502A3752FF618BB3D36 /* ListAppsCommand.swift */,
FD6BB613EC44C1B32CE4A47E /* ListMonitorsCommand.swift */,
9E6478C499F3FB86C017D7BB /* ListWorkspacesCommand.swift */,
D83FDC62BD349F4FDB2D779A /* VersionCommand.swift */,
);
path = query;
Expand Down Expand Up @@ -564,6 +567,7 @@
D12277DFEAAAC7AE19D0B629 /* LazySequenceProtocolEx.swift in Sources */,
63D2357EADCF6137D630F7C5 /* ListAppsCommand.swift in Sources */,
F69159A961FEE54847EC9A8D /* ListMonitorsCommand.swift in Sources */,
3AFD7EE961B97F38C0914A0C /* ListWorkspacesCommand.swift in Sources */,
BD6301B2CFC16FDE4223ACB8 /* MacApp.swift in Sources */,
EECC59858691B99A95542D72 /* MacWindow.swift in Sources */,
6E4E235FDA41307B19F16182 /* ModeCommand.swift in Sources */,
Expand Down
1 change: 1 addition & 0 deletions LocalPackage/Sources/Common/cmdArgs/CmdKind.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public enum CmdKind: String, CaseIterable, Equatable {
case layout
case listApps = "list-apps"
case listMonitors = "list-monitors"
case listWorkspaces = "list-workspaces"
case mode
case move = "move"
case moveNodeToWorkspace = "move-node-to-workspace"
Expand Down
2 changes: 2 additions & 0 deletions LocalPackage/Sources/Common/cmdArgs/parseCmdArgs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ private func initSubcommands() -> [String: any SubCommandParserProtocol] {
result[kind.rawValue] = noArgsSubCommandParser(ListAppsCmdArgs())
case .listMonitors:
result[kind.rawValue] = SubCommandParser(parseListMonitorsCmdArgs)
case .listWorkspaces:
result[kind.rawValue] = SubCommandParser(parseListWorkspaces)
case .mode:
result[kind.rawValue] = SubCommandParser(parseModeCmdArgs)
case .moveNodeToWorkspace:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
private let onitors = "<monitors>"

public struct ListWorkspacesCmdArgs: RawCmdArgs, CmdArgs {
public static let parser: CmdParser<Self> = cmdParser(
kind: .listWorkspaces,
allowInConfig: false,
help: """
USAGE: list-workspaces [-h|--help] [--visible [no]] [--focused [no]] [--mouse [no]]
[--on-monitors \(onitors)]
OPTIONS:
-h, --help Print help
--visible [no] Filter results to only print currently visible workspaces or not
--mouse [no] Filter results to only print the workspace with the mouse or not
--focused [no] Filter results to only print the focused workspace or not
--on-monitors \(onitors) Filter results to only print the workspaces that are attached to specified monitors.
\(onitors) is a comma separated list of monitor IDs
""",
options: [
"--visible": boolFlag(\.visible),
"--mouse": boolFlag(\.mouse),
"--focused": boolFlag(\.focused),
"--on-monitors": ArgParser(\.onMonitors, parseMonitorIds)
],
arguments: []
)

public var visible: Bool?
public var mouse: Bool?
public var focused: Bool?
public var onMonitors: [Int] = []

public init() {}
}

public func parseListWorkspaces(_ args: [String]) -> ParsedCmd<ListWorkspacesCmdArgs> {
parseRawCmdArgs(ListWorkspacesCmdArgs(), args)
}

private func parseMonitorIds(arg: String, nextArgs: inout [String]) -> Parsed<[Int]> {
if let nextArg = nextArgs.nextNonFlagOrNil() {
var monitors: [Int] = []
for monitor in nextArg.split(separator: ",").map({ String($0) }) {
if let unwrapped = Int(monitor) {
monitors.append(unwrapped - 1)
} else {
return .failure("Can't parse '\(monitor)'. It must be a number")
}
}
return .success(monitors)
} else {
return .failure("\(onitors) is mandatory")
}
}
33 changes: 33 additions & 0 deletions docs/aerospace-list-workspaces.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
= aerospace-list-workspaces(1)
include::util/man-attributes.adoc[]
:manname: aerospace-list-workspaces
// tag::purpose[]
:manpurpose: Prints the list of workspaces on new lines
// end::purpose[]

== Synopsis
[verse]
// tag::synopsis[]
list-workspaces [-h|--help] [--visible [no]] [--focused [no]] [--mouse [no]]
[--on-monitors <monitors>]

// end::synopsis[]

== Description

// tag::body[]
{manpurpose}

include::util/conditional-options-header.adoc[]

-h, --help:: Print help
--focused [no]:: Filter results to only print the focused workspace or not
--mouse [no]:: Filter results to only print the workspace with the mouse or not
--focused [no]:: Filter results to only print the focused workspace or not
--on-monitors <monitors>::
Filter results to only print the workspaces that are attached to specified monitors.
<monitors> is a comma separated list of monitor IDs

// end::body[]

include::util/man-footer.adoc[]
2 changes: 1 addition & 1 deletion docs/aerospace-move-node-to-workspace.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ move-node-to-workspace [-h|--help] <workspace-name>
// tag::body[]
{manpurpose}

`*(next|prev)*` is identical to `*workspace (next|prev)*`
`(next|prev)` is identical to `workspace (next|prev)`

// end::body[]

Expand Down
2 changes: 1 addition & 1 deletion docs/aerospace-workspace.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ workspace [-h|--help] [--auto-back-and-forth] <workspace-name>
Focuses next or previous workspace in *the list*.

* If stdin is not TTY and stdin contains non whitespace characters then *the list* is taken from stdin
* Otherwise, *the list* is all workspaces in alphabetical order
* Otherwise, *the list* is defined as all workspaces in alphabetical order

include::util/conditional-options-header.adoc[]

Expand Down
7 changes: 7 additions & 0 deletions docs/commands.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,13 @@ include::aerospace-list-monitors.adoc[tags=synopsis]
include::aerospace-list-monitors.adoc[tags=purpose]
include::aerospace-list-monitors.adoc[tags=body]

=== list-workspaces
----
include::aerospace-list-workspaces.adoc[tags=synopsis]
----
include::aerospace-list-workspaces.adoc[tags=purpose]
include::aerospace-list-workspaces.adoc[tags=body]

=== version
----
include::aerospace-version.adoc[tags=synopsis]
Expand Down
2 changes: 2 additions & 0 deletions src/command/parseCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ extension CmdArgs {
command = ListAppsCommand()
case .listMonitors:
command = ListMonitorsCommand(args: self as! ListMonitorsCmdArgs)
case .listWorkspaces:
command = ListWorkspacesCommand(args: self as! ListWorkspacesCmdArgs)
case .mode:
command = ModeCommand(args: self as! ModeCmdArgs)
case .moveNodeToWorkspace:
Expand Down
36 changes: 36 additions & 0 deletions src/command/query/ListWorkspacesCommand.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import Common

struct ListWorkspacesCommand: Command {
let info: CmdStaticInfo = ListWorkspacesCmdArgs.info
let args: ListWorkspacesCmdArgs

func _run(_ state: CommandMutableState, stdin: String) -> Bool {
check(Thread.current.isMainThread)
var result: [Workspace] = Workspace.all
if let visible = args.visible {
result = result.filter { $0.isVisible == visible }
}
if let mouse = args.mouse {
let mouseWorkspace = mouseLocation.monitorApproximation.activeWorkspace
result = result.filter { ($0 == mouseWorkspace) == mouse }
}
if let focused = args.focused {
result = result.filter { ($0 == Workspace.focused) == focused }
}
if !args.onMonitors.isEmpty {
let sortedMonitors = sortedMonitors
var requested: Set<CGPoint> = []
for id in args.onMonitors {
if let monitor = sortedMonitors.getOrNil(atIndex: id) {
requested.insert(monitor.rect.topLeftCorner)
} else {
state.stdout.append("Invalid monitor ID: \(id)")
return false
}
}
result = result.filter { requested.contains($0.monitor.rect.topLeftCorner) }
}
state.stdout += result.map(\.name)
return true
}
}

0 comments on commit 37956db

Please sign in to comment.