diff --git a/Sources/AppBundle/command/impl/FocusCommand.swift b/Sources/AppBundle/command/impl/FocusCommand.swift index 58713c50..42a0aa82 100644 --- a/Sources/AppBundle/command/impl/FocusCommand.swift +++ b/Sources/AppBundle/command/impl/FocusCommand.swift @@ -32,10 +32,23 @@ struct FocusCommand: Command { return io.err("Can't find window with ID \(windowId)") } case .dfsIndex(let dfsIndex): - if let windowToFocus = target.workspace.rootTilingContainer.allLeafWindowsRecursive.getOrNil(atIndex: Int(dfsIndex)) { + guard let window = target.windowOrNil else { + return io.err("Can't focus window by DFS index without a window") + } + + let allWindows = target.workspace.rootTilingContainer.allLeafWindowsRecursive + + guard let dfsAbsoluteIndex = switch dfsIndex { + case .absolute(let index): index + case .relative(let index): allWindows.firstIndex(of: window).map { $0 + index } + } else { + return io.err("Can't find window in allLeafWindowsRecursive") + } + + if let windowToFocus = allWindows.get(wrappingIndex: dfsAbsoluteIndex) { return windowToFocus.focusWindow() } else { - return io.err("Can't find window with DFS index \(dfsIndex)") + return io.err("Can't find window with DFS index \(dfsAbsoluteIndex)") } } } diff --git a/Sources/Common/cmdArgs/cmdArgsStringArrayEx.swift b/Sources/Common/cmdArgs/cmdArgsStringArrayEx.swift index 483fcc49..1e03b9a0 100644 --- a/Sources/Common/cmdArgs/cmdArgsStringArrayEx.swift +++ b/Sources/Common/cmdArgs/cmdArgsStringArrayEx.swift @@ -7,6 +7,10 @@ extension [String] { first?.starts(with: "-") == true ? nil : nextOrNil() } + mutating func nextNonFullFlagOrNil() -> String? { + first?.starts(with: "--") == true ? nil : nextOrNil() + } + mutating func allNextNonFlagArgs() -> [String] { var args: [String] = [] while let nextArg = nextNonFlagOrNil() { diff --git a/Sources/Common/cmdArgs/impl/FocusCmdArgs.swift b/Sources/Common/cmdArgs/impl/FocusCmdArgs.swift index 5768dd6a..e2637095 100644 --- a/Sources/Common/cmdArgs/impl/FocusCmdArgs.swift +++ b/Sources/Common/cmdArgs/impl/FocusCmdArgs.swift @@ -1,5 +1,6 @@ private let boundar = "" private let actio = "" +private let dfsinde = "" public struct FocusCmdArgs: CmdArgs { public let rawArgs: EquatableNoop<[String]> @@ -13,14 +14,14 @@ public struct FocusCmdArgs: CmdArgs { "--boundaries": ArgParser(\.rawBoundaries, upcastArgParserFun(parseBoundaries)), "--boundaries-action": ArgParser(\.rawBoundariesAction, upcastArgParserFun(parseBoundariesAction)), "--window-id": ArgParser(\.windowId, upcastArgParserFun(parseArgWithUInt32)), - "--dfs-index": ArgParser(\.dfsIndex, upcastArgParserFun(parseArgWithUInt32)), + "--dfs-index": ArgParser(\.dfsIndex, upcastArgParserFun(parseDfsIndex)), ], arguments: [ArgParser(\.direction, upcastArgParserFun(parseCardinalDirectionArg))] ) public var rawBoundaries: Boundaries? = nil // todo cover boundaries wrapping with tests public var rawBoundariesAction: WhenBoundariesCrossed? = nil - public var dfsIndex: UInt32? = nil + public var dfsIndex: DfsIndex? = nil public var direction: CardinalDirection? = nil public var floatingAsTiling: Bool = true public var windowId: UInt32? @@ -36,7 +37,7 @@ public struct FocusCmdArgs: CmdArgs { self.windowId = windowId } - public init(rawArgs: [String], dfsIndex: UInt32) { + public init(rawArgs: [String], dfsIndex: DfsIndex) { self.rawArgs = .init(rawArgs) self.dfsIndex = dfsIndex } @@ -55,7 +56,7 @@ public struct FocusCmdArgs: CmdArgs { public enum FocusCmdTarget { case direction(CardinalDirection) case windowId(UInt32) - case dfsIndex(UInt32) + case dfsIndex(DfsIndex) } public extension FocusCmdArgs { @@ -109,3 +110,23 @@ private func parseBoundaries(arg: String, nextArgs: inout [String]) -> Parsed Parsed { + guard let arg = nextArgs.nextNonFullFlagOrNil() else { + return .failure("\(dfsinde) is mandatory") + } + + // Handle relative indices with + or - prefix + if arg.hasPrefix("+") || arg.hasPrefix("-") { + if let value = Int(arg) { + return .success(.relative(value)) + } + return .failure("Invalid relative DFS index format") + } + + // Handle absolute indices (no prefix) + if let value = Int(arg) { + return .success(.absolute(value)) + } + return .failure("Invalid DFS index format") +} diff --git a/Sources/Common/model/dfsIndex.swift b/Sources/Common/model/dfsIndex.swift new file mode 100644 index 00000000..df44750c --- /dev/null +++ b/Sources/Common/model/dfsIndex.swift @@ -0,0 +1,4 @@ +public enum DfsIndex: Equatable { + case absolute(Int) + case relative(Int) +}