diff --git a/src/command/CloseAllWindowsButCurrentCommand.swift b/src/command/CloseAllWindowsButCurrentCommand.swift index bd32324b..9e3181c4 100644 --- a/src/command/CloseAllWindowsButCurrentCommand.swift +++ b/src/command/CloseAllWindowsButCurrentCommand.swift @@ -1,6 +1,6 @@ class CloseAllWindowsButCurrentCommand: Command { func runWithoutRefresh() { - precondition(Thread.current.isMainThread) + check(Thread.current.isMainThread) guard let focused = focusedWindowOrEffectivelyFocused else { return } for window in focused.workspace.allLeafWindowsRecursive { if window != focused { diff --git a/src/command/CompositeCommand.swift b/src/command/CompositeCommand.swift index 92c278e8..c8659ed0 100644 --- a/src/command/CompositeCommand.swift +++ b/src/command/CompositeCommand.swift @@ -2,7 +2,7 @@ struct CompositeCommand: Command { // todo drop let subCommands: [Command] func runWithoutRefresh() async { - precondition(Thread.current.isMainThread) + check(Thread.current.isMainThread) for command in subCommands { await command.runWithoutRefresh() } diff --git a/src/command/ExecAndForgetCommand.swift b/src/command/ExecAndForgetCommand.swift index 1a8570dc..ece145c9 100644 --- a/src/command/ExecAndForgetCommand.swift +++ b/src/command/ExecAndForgetCommand.swift @@ -2,7 +2,7 @@ struct ExecAndForgetCommand: Command { let bashCommand: String func runWithoutRefresh() { - precondition(Thread.current.isMainThread) + check(Thread.current.isMainThread) // It doesn't throw if exit code is non-zero try! Process.run(URL(filePath: "/bin/bash"), arguments: ["-c", bashCommand]) } diff --git a/src/command/ExecAndWaitCommand.swift b/src/command/ExecAndWaitCommand.swift index f50151a7..b96a4161 100644 --- a/src/command/ExecAndWaitCommand.swift +++ b/src/command/ExecAndWaitCommand.swift @@ -2,7 +2,7 @@ struct ExecAndWaitCommand: Command { let bashCommand: String func runWithoutRefresh() async { - precondition(Thread.current.isMainThread) + check(Thread.current.isMainThread) await withCheckedContinuation { (continuation: CheckedContinuation<(), Never>) in let process = Process() process.executableURL = URL(filePath: "/bin/bash") diff --git a/src/command/FlattenWorkspaceTreeCommand.swift b/src/command/FlattenWorkspaceTreeCommand.swift index 1e3a450b..13ea1207 100644 --- a/src/command/FlattenWorkspaceTreeCommand.swift +++ b/src/command/FlattenWorkspaceTreeCommand.swift @@ -1,6 +1,6 @@ struct FlattenWorkspaceTreeCommand: Command { func runWithoutRefresh() { - precondition(Thread.current.isMainThread) + check(Thread.current.isMainThread) guard let currentWindow = focusedWindowOrEffectivelyFocused else { return } let workspace = currentWindow.workspace let windows = workspace.rootTilingContainer.allLeafWindowsRecursive diff --git a/src/command/FocusCommand.swift b/src/command/FocusCommand.swift index 52593804..8165780e 100644 --- a/src/command/FocusCommand.swift +++ b/src/command/FocusCommand.swift @@ -2,7 +2,7 @@ struct FocusCommand: Command { let direction: CardinalDirection func runWithoutRefresh() { - precondition(Thread.current.isMainThread) + check(Thread.current.isMainThread) guard let currentWindow = focusedWindowOrEffectivelyFocused else { return } guard let (parent, ownIndex) = currentWindow.closestParent(hasChildrenInDirection: direction, withLayout: nil) else { return } let windowToFocus = parent.children[ownIndex + direction.focusOffset] diff --git a/src/command/LayoutCommand.swift b/src/command/LayoutCommand.swift index 3aaea5bb..1aa50737 100644 --- a/src/command/LayoutCommand.swift +++ b/src/command/LayoutCommand.swift @@ -11,7 +11,7 @@ struct LayoutCommand: Command { } func runWithoutRefresh() { - precondition(Thread.current.isMainThread) + check(Thread.current.isMainThread) guard let window = focusedWindowOrEffectivelyFocused else { return } let targetLayout: ConfigLayout = toggleBetween.firstIndex(of: window.configLayout) .flatMap { toggleBetween.getOrNil(atIndex: $0 + 1) } diff --git a/src/command/ModeCommand.swift b/src/command/ModeCommand.swift index 30333a6e..63d67599 100644 --- a/src/command/ModeCommand.swift +++ b/src/command/ModeCommand.swift @@ -2,7 +2,7 @@ struct ModeCommand: Command { let idToActivate: String func runWithoutRefresh() { - precondition(Thread.current.isMainThread) + check(Thread.current.isMainThread) activateMode(idToActivate) } } diff --git a/src/command/MoveInCommand.swift b/src/command/MoveInCommand.swift index 5161ea86..a6592486 100644 --- a/src/command/MoveInCommand.swift +++ b/src/command/MoveInCommand.swift @@ -2,7 +2,7 @@ struct MoveInCommand: Command { let direction: CardinalDirection func runWithoutRefresh() { - precondition(Thread.current.isMainThread) + check(Thread.current.isMainThread) guard let currentWindow = focusedWindowOrEffectivelyFocused else { return } guard let (parent, ownIndex) = currentWindow.closestParent(hasChildrenInDirection: direction, withLayout: nil) else { return } let moveInTarget = parent.children[ownIndex + direction.focusOffset] diff --git a/src/command/MoveThroughCommand.swift b/src/command/MoveThroughCommand.swift index bd899d89..186b80de 100644 --- a/src/command/MoveThroughCommand.swift +++ b/src/command/MoveThroughCommand.swift @@ -2,7 +2,7 @@ struct MoveThroughCommand: Command { let direction: CardinalDirection func runWithoutRefresh() { - precondition(Thread.current.isMainThread) + check(Thread.current.isMainThread) guard let currentWindow = focusedWindowOrEffectivelyFocused else { return } switch currentWindow.parent.kind { case .tilingContainer(let parent): @@ -40,13 +40,13 @@ private func moveOut(window: Window, direction: CardinalDirection) { let bindToIndex: Int switch innerMostChild.parent.genericKind { case .tilingContainer(let parent): - precondition(parent.orientation == direction.orientation) + check(parent.orientation == direction.orientation) bindTo = parent bindToIndex = innerMostChild.ownIndex + direction.insertionOffset case .workspace(let parent): // create implicit container let prevRoot = parent.rootTilingContainer prevRoot.unbindFromParent() - precondition(prevRoot != parent.rootTilingContainer) + check(prevRoot != parent.rootTilingContainer) parent.rootTilingContainer.orientation = direction.orientation parent.rootTilingContainer.layout = .list // todo force List layout for implicit containers? prevRoot.bindTo(parent: parent.rootTilingContainer, adaptiveWeight: WEIGHT_AUTO) diff --git a/src/command/MoveWorkspaceToDisplayCommand.swift b/src/command/MoveWorkspaceToDisplayCommand.swift index f9a01a88..bda29918 100644 --- a/src/command/MoveWorkspaceToDisplayCommand.swift +++ b/src/command/MoveWorkspaceToDisplayCommand.swift @@ -6,7 +6,7 @@ struct MoveWorkspaceToDisplayCommand: Command { } func runWithoutRefresh() { - precondition(Thread.current.isMainThread) + check(Thread.current.isMainThread) let focusedWorkspace = Workspace.focused let prevMonitor = focusedWorkspace.monitor let sortedMonitors = sortedMonitors diff --git a/src/command/ReloadConfigCommand.swift b/src/command/ReloadConfigCommand.swift index bea7d61b..0503a3be 100644 --- a/src/command/ReloadConfigCommand.swift +++ b/src/command/ReloadConfigCommand.swift @@ -1,6 +1,6 @@ struct ReloadConfigCommand: Command { func runWithoutRefresh() { - precondition(Thread.current.isMainThread) + check(Thread.current.isMainThread) reloadConfig() } } diff --git a/src/command/ResizeCommand.swift b/src/command/ResizeCommand.swift index de60d027..279c9907 100644 --- a/src/command/ResizeCommand.swift +++ b/src/command/ResizeCommand.swift @@ -7,7 +7,7 @@ struct ResizeCommand: Command { // todo cover with tests let diff: Int func runWithoutRefresh() { // todo support key repeat - precondition(Thread.current.isMainThread) + check(Thread.current.isMainThread) guard let window = focusedWindowOrEffectivelyFocused else { return } switch window.parent.kind { diff --git a/src/command/WorkspaceBackAndForthCommand.swift b/src/command/WorkspaceBackAndForthCommand.swift index 7eeb2aaf..8d63305d 100644 --- a/src/command/WorkspaceBackAndForthCommand.swift +++ b/src/command/WorkspaceBackAndForthCommand.swift @@ -1,6 +1,6 @@ struct WorkspaceBackAndForthCommand: Command { func runWithoutRefresh() { - precondition(Thread.current.isMainThread) + check(Thread.current.isMainThread) guard let previousFocusedWorkspaceName else { return } WorkspaceCommand(workspaceName: previousFocusedWorkspaceName).runWithoutRefresh() } diff --git a/src/command/WorkspaceCommand.swift b/src/command/WorkspaceCommand.swift index 389b99f6..9673d963 100644 --- a/src/command/WorkspaceCommand.swift +++ b/src/command/WorkspaceCommand.swift @@ -2,7 +2,7 @@ struct WorkspaceCommand : Command { let workspaceName: String func runWithoutRefresh() { - precondition(Thread.current.isMainThread) + check(Thread.current.isMainThread) let workspace = Workspace.get(byName: workspaceName) // todo drop anyLeafWindowRecursive. It must not be necessary if let window = workspace.mostRecentWindow ?? workspace.anyLeafWindowRecursive { // switch to not empty workspace @@ -16,7 +16,7 @@ struct WorkspaceCommand : Command { window.focus() // The switching itself will be done by refreshWorkspaces and layoutWorkspaces later in refresh } else { // switch to empty workspace - precondition(workspace.isEffectivelyEmpty) + check(workspace.isEffectivelyEmpty) workspace.monitor.setActiveWorkspace(workspace) focusedWorkspaceName = workspace.name focusedWorkspaceSourceOfTruth = .ownModel diff --git a/src/focused.swift b/src/focused.swift index 2a027d7c..1385efdc 100644 --- a/src/focused.swift +++ b/src/focused.swift @@ -5,7 +5,7 @@ var focusedApp: AeroApp? { if isUnitTest { return appForTests } else { - precondition(appForTests == nil) + check(appForTests == nil) if NSWorkspace.shared.frontmostApplication == _focusedApp { _focusedApp = nil } diff --git a/src/mouse/resizeWithMouse.swift b/src/mouse/resizeWithMouse.swift index b1e4a85b..ec9f6557 100644 --- a/src/mouse/resizeWithMouse.swift +++ b/src/mouse/resizeWithMouse.swift @@ -6,7 +6,7 @@ func resizedObs(_ obs: AXObserver, ax: AXUIElement, notif: CFString, data: Unsaf } func resetManipulatedWithMouseIfPossible() { - precondition(Thread.current.isMainThread) + check(Thread.current.isMainThread) if currentlyManipulatedWithMouseWindowId != nil { currentlyManipulatedWithMouseWindowId = nil for workspace in Workspace.all { diff --git a/src/refresh.swift b/src/refresh.swift index cf7a92b2..752e4f93 100644 --- a/src/refresh.swift +++ b/src/refresh.swift @@ -1,7 +1,7 @@ /// It's one of the most important function of the whole application. /// The function is called as a feedback response on every user input func refresh(startup: Bool = false) { - precondition(Thread.current.isMainThread) + check(Thread.current.isMainThread) //debug("refresh \(Date.now.formatted(date: .abbreviated, time: .standard))") // Garbage collect terminated apps and windows before working with all windows diff --git a/src/tree/AeroApp.swift b/src/tree/AeroApp.swift index 764e46b4..19e7a1b6 100644 --- a/src/tree/AeroApp.swift +++ b/src/tree/AeroApp.swift @@ -7,10 +7,10 @@ class AeroApp: Hashable { static func ==(lhs: AeroApp, rhs: AeroApp) -> Bool { if lhs.id == rhs.id { - precondition(lhs === rhs) + check(lhs === rhs) return true } else { - precondition(lhs !== rhs) + check(lhs !== rhs) return false } } diff --git a/src/tree/TreeNode.swift b/src/tree/TreeNode.swift index c3d67ccd..f9f4cc6d 100644 --- a/src/tree/TreeNode.swift +++ b/src/tree/TreeNode.swift @@ -96,7 +96,7 @@ class TreeNode: Equatable { guard let _parent else { return nil } let index = _parent._children.remove(element: self) ?? errorT("Can't find child in its parent") - precondition(_parent._mruChildren.remove(self)) + check(_parent._mruChildren.remove(self)) self._parent = nil return BindingData(parent: _parent, adaptiveWeight: adaptiveWeight, index: index) diff --git a/src/tree/TreeNodeEx.swift b/src/tree/TreeNodeEx.swift index c7e14f3d..26a64584 100644 --- a/src/tree/TreeNodeEx.swift +++ b/src/tree/TreeNodeEx.swift @@ -110,7 +110,7 @@ extension TreeNode { })! switch innermostChild.parent?.kind { case .tilingContainer(let parent): - precondition(parent.orientation == direction.orientation) + check(parent.orientation == direction.orientation) return (parent, innermostChild.ownIndexOrNil!) case .workspace, nil: return nil diff --git a/src/tree/Workspace.swift b/src/tree/Workspace.swift index adb9288b..408f335d 100644 --- a/src/tree/Workspace.swift +++ b/src/tree/Workspace.swift @@ -158,7 +158,7 @@ private func rearrangeWorkspacesOnMonitors() { var preservedOldScreens: [CGPoint] = [] for newScreen in newScreens { if let oldScreen = oldVisibleScreens.minBy({ ($0 - newScreen).vectorLength }) { - precondition(oldVisibleScreens.remove(oldScreen) != nil) + check(oldVisibleScreens.remove(oldScreen) != nil) newScreenToOldScreenMapping[newScreen] = oldScreen preservedOldScreens.append(oldScreen) } diff --git a/src/util/accessibility.swift b/src/util/accessibility.swift index af71e9a2..d6c18f65 100644 --- a/src/util/accessibility.swift +++ b/src/util/accessibility.swift @@ -197,7 +197,7 @@ enum Ax { key: kAXSizeAttribute, getter: { var raw: CGSize = .zero - precondition(AXValueGetValue($0 as! AXValue, .cgSize, &raw)) + check(AXValueGetValue($0 as! AXValue, .cgSize, &raw)) return raw }, setter: { @@ -272,7 +272,7 @@ extension AXUIElement { extension AXObserver { private static func newImpl(_ pid: pid_t, _ handler: AXObserverCallback) -> AXObserver { var observer: AXObserver? = nil - precondition(AXObserverCreate(pid, handler, &observer) == .success) + check(AXObserverCreate(pid, handler, &observer) == .success) return observer! } diff --git a/src/util/util.swift b/src/util/util.swift index a83aec2f..ef6739fa 100644 --- a/src/util/util.swift +++ b/src/util/util.swift @@ -5,6 +5,19 @@ func stringType(of some: Any) -> String { return string } +func check( + _ condition: Bool, + _ message: String = "", + file: String = #file, + line: Int = #line, + column: Int = #column, + function: String = #function +) { + if !condition { + error(message, file: file, line: line, column: column, function: function) + } +} + @inlinable func errorT( _ message: String = "", file: String = #file, diff --git a/test/testUtil.swift b/test/testUtil.swift index db704966..3233c6f5 100644 --- a/test/testUtil.swift +++ b/test/testUtil.swift @@ -28,8 +28,8 @@ func setUpWorkspacesForTests() { focusedWorkspaceSourceOfTruth = .defaultSourceOfTruth focusedWorkspaceName = mainMonitor.activeWorkspace.name Workspace.garbageCollectUnusedWorkspaces() - precondition(Workspace.focused.isEffectivelyEmpty) - precondition(Workspace.focused === Workspace.all.singleOrNil(), Workspace.all.map(\.description).joined(separator: ", ")) + check(Workspace.focused.isEffectivelyEmpty) + check(Workspace.focused === Workspace.all.singleOrNil(), Workspace.all.map(\.description).joined(separator: ", ")) TestApp.shared.focusedWindow = nil TestApp.shared.windows = [] diff --git a/test/tree/TestApp.swift b/test/tree/TestApp.swift index 509e8bb2..067c62e5 100644 --- a/test/tree/TestApp.swift +++ b/test/tree/TestApp.swift @@ -12,7 +12,7 @@ final class TestApp: AeroApp { get { _windows } set { if let focusedWindow { - precondition(newValue.contains(focusedWindow)) + check(newValue.contains(focusedWindow)) } _windows = newValue } @@ -23,7 +23,7 @@ final class TestApp: AeroApp { get { _focusedWindow } set { if let window = newValue { - precondition(windows.contains(window)) + check(windows.contains(window)) } _focusedWindow = newValue }