Skip to content

Commit

Permalink
Fix exec-and-wait
Browse files Browse the repository at this point in the history
  • Loading branch information
nikitabobko committed Nov 25, 2023
1 parent f992d74 commit 7e21b77
Show file tree
Hide file tree
Showing 26 changed files with 70 additions and 77 deletions.
4 changes: 0 additions & 4 deletions AeroSpace.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@
D24D02B1FD87424B908986AF /* ResizeCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB371951459F8CB0137788C2 /* ResizeCommand.swift */; };
D4281F11EC10B5CD6470DF97 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 083785CBAE36EC57F5F51BC8 /* main.swift */; };
DCCC05496BDAAFB745E99624 /* SplitCommandTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D96FF3675C63A83DC8B8969 /* SplitCommandTest.swift */; };
E1E35DC5D9D74D54E92AB5F3 /* ExecCommandTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A6EF465EF4129BCB10FE247 /* ExecCommandTest.swift */; };
E22ACB36C90695FBAC78226E /* TestWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F1905935B0C61590A96EFEF /* TestWindow.swift */; };
E23E3E87A0C2798E9F87EDEA /* Socket in Frameworks */ = {isa = PBXBuildFile; productRef = 82F718CE1C9CF9EB5A80DDE7 /* Socket */; };
E5682579AEC6B84CF6FCE90D /* TilingContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C848D6E57FDF22AAF0FB45E6 /* TilingContainer.swift */; };
Expand Down Expand Up @@ -129,7 +128,6 @@
25AC44D0E9450867215FCBEC /* MoveNodeToWorkspaceCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoveNodeToWorkspaceCommand.swift; sourceTree = "<group>"; };
2D96FF3675C63A83DC8B8969 /* SplitCommandTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplitCommandTest.swift; sourceTree = "<group>"; };
3A262B442A94C1964509B691 /* TreeNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TreeNode.swift; sourceTree = "<group>"; };
3A6EF465EF4129BCB10FE247 /* ExecCommandTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExecCommandTest.swift; sourceTree = "<group>"; };
3C2E5977331398421A4FC168 /* GlobalObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalObserver.swift; sourceTree = "<group>"; };
43DD32B1711B8EFCC834B68E /* WorkspaceCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkspaceCommand.swift; sourceTree = "<group>"; };
458AD0CD907B56A99DA821C4 /* AeroSpace-cli */ = {isa = PBXFileReference; includeInIndex = 0; path = "AeroSpace-cli"; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -251,7 +249,6 @@
23BD2F40E261F3F94B75149A /* command */ = {
isa = PBXGroup;
children = (
3A6EF465EF4129BCB10FE247 /* ExecCommandTest.swift */,
53FDECECC773EBA30661EB8A /* FlattenWorkspaceTreeCommandTest.swift */,
D0EAADE8D2FB5D05FA5456B0 /* FocusCommandTest.swift */,
6D9C5ED5AC77D80F1CCD103F /* JoinWithCommandTest.swift */,
Expand Down Expand Up @@ -578,7 +575,6 @@
buildActionMask = 2147483647;
files = (
E7F53669DD11FA7C6C3540A0 /* ConfigTest.swift in Sources */,
E1E35DC5D9D74D54E92AB5F3 /* ExecCommandTest.swift in Sources */,
374CE35B85B941B8F584C113 /* FlattenWorkspaceTreeCommandTest.swift in Sources */,
1311398A83B998908773C54D /* FocusCommandTest.swift in Sources */,
8FD14C98B263A6CA0174DDF1 /* JoinWithCommandTest.swift in Sources */,
Expand Down
15 changes: 9 additions & 6 deletions src/AeroSpaceApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,13 @@ struct AeroSpaceApp: App {
startServer()
GlobalObserver.initObserver()
refreshAndLayout()
if startedAtLogin {
config.afterLoginCommand.run()
refreshSession {
var focused = CommandSubject.focused
if startedAtLogin {
config.afterLoginCommand.run(&focused)
}
config.afterStartupCommand.run(&focused)
}
config.afterStartupCommand.run()
}
}

Expand All @@ -44,7 +47,7 @@ struct AeroSpaceApp: App {
Text("Workspaces:")
ForEach(Workspace.all) { (workspace: Workspace) in
Button {
refreshSession { WorkspaceCommand(workspaceName: workspace.name).run() }
refreshSession { WorkspaceCommand(workspaceName: workspace.name).runOnFocusedSubject() }
} label: {
Toggle(isOn: workspace == Workspace.focused
? Binding(get: { true }, set: { _, _ in })
Expand All @@ -56,11 +59,11 @@ struct AeroSpaceApp: App {
}
Divider()
Button(viewModel.isEnabled ? "Disable" : "Enable") {
refreshSession { EnableCommand(targetState: .toggle).run() }
refreshSession { EnableCommand(targetState: .toggle).runOnFocusedSubject() }
}
.keyboardShortcut("E", modifiers: .command)
Button("Reload config") {
refreshSession { ReloadConfigCommand().run() }
refreshSession { ReloadConfigCommand().runOnFocusedSubject() }
}
.keyboardShortcut("R", modifiers: .command)
Button("Quit \(Bundle.appName)") {
Expand Down
2 changes: 1 addition & 1 deletion src/command/CloseAllWindowsButCurrentCommand.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class CloseAllWindowsButCurrentCommand: Command {
func runWithoutLayout(subject: inout CommandSubject) {
func _run(_ subject: inout CommandSubject, _ index: Int, _ commands: [any Command]) {
check(Thread.current.isMainThread)
guard let focused = subject.windowOrNil else { return }
for window in focused.workspace.allLeafWindowsRecursive {
Expand Down
34 changes: 19 additions & 15 deletions src/command/Command.swift
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
protocol Command: AeroAny { // todo add exit code and messages
func runWithoutLayout(subject: inout CommandSubject)
func _run(_ subject: inout CommandSubject, _ index: Int, _ commands: [any Command])
}

protocol QueryCommand {
func run() -> String
}

extension Command {
func run() {
func run(_ subject: inout CommandSubject) {
check(Thread.current.isMainThread)
[self].run()
[self].run(&subject)
}

func runOnFocusedSubject() {
var focused = CommandSubject.focused
run(&focused)
}

var isExec: Bool { self is ExecAndWaitCommand || self is ExecAndForgetCommand }
Expand All @@ -20,30 +25,29 @@ extension Command {
// 2. CLI requests to server
// 3. on-window-detected callback
extension [Command] {
func run(_ initSubject: CommandSubject? = nil) { // todo make parameter mandatory
func run(_ subject: inout CommandSubject) {
check(Thread.current.isMainThread)
// todo commands that come after enable must be run as well
// todo what about disabled server for on-window-detected commands?
let commands = TrayMenuModel.shared.isEnabled ? self : (singleOrNil() as? EnableCommand).asList()
var subject: CommandSubject
if let initSubject {
subject = initSubject
} else if let window = focusedWindow {
subject = .window(window)
} else {
subject = .emptyWorkspace(focusedWorkspaceName)
}
for command in commands {
command.runWithoutLayout(subject: &subject)
for (index, command) in commands.withIndex {
command._run(&subject, index, self)
refreshModel(startup: false)
}
}

}

enum CommandSubject {
case emptyWorkspace(String)
case window(Window)

static var focused: CommandSubject {
if let window = focusedWindow {
return .window(window)
} else {
return .emptyWorkspace(focusedWorkspaceName)
}
}
}

extension CommandSubject {
Expand Down
2 changes: 1 addition & 1 deletion src/command/EnableCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ struct EnableCommand: Command {

let targetState: State

func runWithoutLayout(subject: inout CommandSubject) {
func _run(_ subject: inout CommandSubject, _ index: Int, _ commands: [any Command]) {
check(Thread.current.isMainThread)
let prevState = TrayMenuModel.shared.isEnabled
let newState: Bool
Expand Down
3 changes: 2 additions & 1 deletion src/command/ExecAndForgetCommand.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
struct ExecAndForgetCommand: Command {
let bashCommand: String

func runWithoutLayout(subject: inout CommandSubject) {
func _run(_ subject: inout CommandSubject, _ index: Int, _ commands: [any Command]) {
// todo shall exec-and-forget fork exec session?
check(Thread.current.isMainThread)
// It doesn't throw if exit code is non-zero
try! Process.run(URL(filePath: "/bin/bash"), arguments: ["-c", bashCommand])
Expand Down
24 changes: 12 additions & 12 deletions src/command/ExecAndWaitCommand.swift
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
struct ExecAndWaitCommand: Command {
let bashCommand: String

func runWithoutLayout(subject: inout CommandSubject) {
func _run(_ subject: inout CommandSubject, _ index: Int, _ commands: [any Command]) {
check(Thread.current.isMainThread)
// todo drop async await and run new session instead
//error("TODO")
//await withCheckedContinuation { (continuation: CheckedContinuation<(), Never>) in
let process = Process()
process.executableURL = URL(filePath: "/bin/bash")
process.arguments = ["-c", bashCommand]
process.terminationHandler = { _ in
//continuation.resume()
let process = Process()
process.executableURL = URL(filePath: "/bin/bash")
process.arguments = ["-c", bashCommand]
process.terminationHandler = { _ in
check(Thread.current.isMainThread)
refreshSession {
var focused = CommandSubject.focused
Array(commands[(index + 1)...]).run(&focused) // todo preserve subject in "exec sessions"
}
// It doesn't throw if exit code is non-zero
try! process.run()
//}
}
// It doesn't throw if exit code is non-zero
try! process.run()
}
}
2 changes: 1 addition & 1 deletion src/command/FlattenWorkspaceTreeCommand.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
struct FlattenWorkspaceTreeCommand: Command {
func runWithoutLayout(subject: inout CommandSubject) {
func _run(_ subject: inout CommandSubject, _ index: Int, _ commands: [any Command]) {
check(Thread.current.isMainThread)
let workspace = subject.workspace
let windows = workspace.rootTilingContainer.allLeafWindowsRecursive
Expand Down
2 changes: 1 addition & 1 deletion src/command/FocusCommand.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
struct FocusCommand: Command {
let direction: CardinalDirection

func runWithoutLayout(subject: inout CommandSubject) {
func _run(_ subject: inout CommandSubject, _ index: Int, _ commands: [any Command]) {
check(Thread.current.isMainThread)
guard let currentWindow = subject.windowOrNil else { return }
let workspace = currentWindow.workspace
Expand Down
2 changes: 1 addition & 1 deletion src/command/FullscreenCommand.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
struct FullscreenCommand: Command {
func runWithoutLayout(subject: inout CommandSubject) {
func _run(_ subject: inout CommandSubject, _ index: Int, _ commands: [any Command]) {
check(Thread.current.isMainThread)
guard let window = subject.windowOrNil else { return }
window.isFullscreen = !window.isFullscreen
Expand Down
2 changes: 1 addition & 1 deletion src/command/JoinWithCommand.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
struct JoinWithCommand: Command {
let direction: CardinalDirection

func runWithoutLayout(subject: inout CommandSubject) {
func _run(_ subject: inout CommandSubject, _ index: Int, _ commands: [any Command]) {
check(Thread.current.isMainThread)
guard let currentWindow = subject.windowOrNil else { return }
guard let (parent, ownIndex) = currentWindow.closestParent(hasChildrenInDirection: direction, withLayout: nil) else { return }
Expand Down
2 changes: 1 addition & 1 deletion src/command/LayoutCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ struct LayoutCommand: Command {
self.toggleBetween = toggleBetween
}

func runWithoutLayout(subject: inout CommandSubject) {
func _run(_ subject: inout CommandSubject, _ index: Int, _ commands: [any Command]) {
check(Thread.current.isMainThread)
guard let window = subject.windowOrNil else { return }
let targetDescription: LayoutDescription = toggleBetween.first(where: { !window.matchesDescription($0) })
Expand Down
2 changes: 1 addition & 1 deletion src/command/ModeCommand.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
struct ModeCommand: Command {
let idToActivate: String

func runWithoutLayout(subject: inout CommandSubject) {
func _run(_ subject: inout CommandSubject, _ index: Int, _ commands: [any Command]) {
check(Thread.current.isMainThread)
activateMode(idToActivate)
}
Expand Down
2 changes: 1 addition & 1 deletion src/command/MoveNodeToWorkspaceCommand.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
struct MoveNodeToWorkspaceCommand: Command {
let targetWorkspaceName: String

func runWithoutLayout(subject: inout CommandSubject) {
func _run(_ subject: inout CommandSubject, _ index: Int, _ commands: [any Command]) {
guard let focused = subject.windowOrNil else { return }
let preserveWorkspace = focused.workspace
let targetWorkspace = Workspace.get(byName: targetWorkspaceName)
Expand Down
2 changes: 1 addition & 1 deletion src/command/MoveThroughCommand.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
struct MoveThroughCommand: Command {
let direction: CardinalDirection

func runWithoutLayout(subject: inout CommandSubject) {
func _run(_ subject: inout CommandSubject, _ index: Int, _ commands: [any Command]) {
check(Thread.current.isMainThread)
guard let currentWindow = subject.windowOrNil else { return }
switch currentWindow.parent.kind {
Expand Down
2 changes: 1 addition & 1 deletion src/command/MoveWorkspaceToMonitorCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ struct MoveWorkspaceToMonitorCommand: Command {
case next, prev
}

func runWithoutLayout(subject: inout CommandSubject) {
func _run(_ subject: inout CommandSubject, _ index: Int, _ commands: [any Command]) {
check(Thread.current.isMainThread)
let focusedWorkspace = subject.workspace
let prevMonitor = focusedWorkspace.monitor
Expand Down
2 changes: 1 addition & 1 deletion src/command/ReloadConfigCommand.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
struct ReloadConfigCommand: Command {
func runWithoutLayout(subject: inout CommandSubject) {
func _run(_ subject: inout CommandSubject, _ index: Int, _ commands: [any Command]) {
check(Thread.current.isMainThread)
reloadConfig()
}
Expand Down
2 changes: 1 addition & 1 deletion src/command/ResizeCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ struct ResizeCommand: Command { // todo cover with tests
let mode: ResizeMode
let unit: UInt

func runWithoutLayout(subject: inout CommandSubject) { // todo support key repeat
func _run(_ subject: inout CommandSubject, _ index: Int, _ commands: [any Command]) { // todo support key repeat
check(Thread.current.isMainThread)

let candidates = subject.windowOrNil?.parentsWithSelf
Expand Down
2 changes: 1 addition & 1 deletion src/command/SplitCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ struct SplitCommand: Command {

let splitArg: SplitArg

func runWithoutLayout(subject: inout CommandSubject) {
func _run(_ subject: inout CommandSubject, _ index: Int, _ commands: [any Command]) {
check(Thread.current.isMainThread)
if config.enableNormalizationFlattenContainers {
return // 'split' doesn't work with "flatten container" normalization enabled
Expand Down
4 changes: 2 additions & 2 deletions src/command/WorkspaceBackAndForthCommand.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
struct WorkspaceBackAndForthCommand: Command {
func runWithoutLayout(subject: inout CommandSubject) {
func _run(_ subject: inout CommandSubject, _ index: Int, _ commands: [any Command]) {
check(Thread.current.isMainThread)
guard let previousFocusedWorkspaceName else { return }
WorkspaceCommand(workspaceName: previousFocusedWorkspaceName).runWithoutLayout(subject: &subject)
WorkspaceCommand(workspaceName: previousFocusedWorkspaceName).run(&subject)
}
}
2 changes: 1 addition & 1 deletion src/command/WorkspaceCommand.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
struct WorkspaceCommand : Command {
let workspaceName: String

func runWithoutLayout(subject: inout CommandSubject) {
func _run(_ subject: inout CommandSubject, _ index: Int, _ commands: [any Command]) {
check(Thread.current.isMainThread)
let workspace = Workspace.get(byName: workspaceName)
if let window = workspace.mostRecentWindow { // switch to not empty workspace
Expand Down
5 changes: 4 additions & 1 deletion src/config/Config.swift
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,10 @@ class HotkeyBinding {

func activate() {
hotKey = HotKey(key: key, modifiers: modifiers, keyUpHandler: { [commands] in
refreshSession { commands.run() }
refreshSession {
var subject = CommandSubject.focused
commands.run(&subject)
}
})
}

Expand Down
5 changes: 4 additions & 1 deletion src/server.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ private func newConnection(_ socket: Socket) async { // todo add exit codes
continue
}
if let action {
action.run()
_ = await Task { @MainActor in
var focused = CommandSubject.focused // todo restore subject from "exec session"
action.run(&focused)
}.result
_ = try? socket.write(from: "PASS")
continue
}
Expand Down
3 changes: 2 additions & 1 deletion src/tree/MacWindow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,8 @@ func onWindowDetected(_ window: Window) {
check(Thread.current.isMainThread)
for callback in config.onWindowDetected {
if callback.matches(window) {
callback.run.run(.window(window))
var subject = CommandSubject.window(window)
callback.run.run(&subject)
}
}
}
Expand Down
18 changes: 0 additions & 18 deletions test/command/ExecCommandTest.swift

This file was deleted.

2 changes: 1 addition & 1 deletion test/command/FocusCommandTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ extension Command {
} else {
state = .emptyWorkspace(focusedWorkspaceName)
}
runWithoutLayout(subject: &state)
run(&state)
state.windowOrNil?.focus()
}
}

0 comments on commit 7e21b77

Please sign in to comment.