diff --git a/CLI/cmuxterm.swift b/CLI/cmuxterm.swift index d33cd62b..2d3748a2 100644 --- a/CLI/cmuxterm.swift +++ b/CLI/cmuxterm.swift @@ -192,10 +192,12 @@ struct CMUXCLI { print(response) case "new-split": - guard let direction = commandArgs.first else { + let (panelArg, remaining) = parseOption(commandArgs, name: "--panel") + guard let direction = remaining.first else { throw CLIError(message: "new-split requires a direction") } - let response = try client.send(command: "new_split \(direction)") + let cmd = panelArg != nil ? "new_split \(direction) \(panelArg!)" : "new_split \(direction)" + let response = try client.send(command: cmd) print(response) case "list-panels": @@ -509,7 +511,7 @@ struct CMUXCLI { ping list-tabs new-tab - new-split + new-split [--panel ] list-panels [--tab ] focus-panel --panel close-tab --tab diff --git a/Sources/GhosttyTerminalView.swift b/Sources/GhosttyTerminalView.swift index 430dde1e..2b0cdf17 100644 --- a/Sources/GhosttyTerminalView.swift +++ b/Sources/GhosttyTerminalView.swift @@ -429,7 +429,7 @@ class GhosttyApp { return false } return performOnMain { - tabManager.newSplit(tabId: tabId, surfaceId: surfaceId, direction: direction) + tabManager.newSplit(tabId: tabId, surfaceId: surfaceId, direction: direction) != nil } case GHOSTTY_ACTION_GOTO_SPLIT: guard let tabId = surfaceView.tabId, diff --git a/Sources/TabManager.swift b/Sources/TabManager.swift index 81745b4a..3634d5ee 100644 --- a/Sources/TabManager.swift +++ b/Sources/TabManager.swift @@ -764,9 +764,9 @@ class TabManager: ObservableObject { } } - func newSplit(tabId: UUID, surfaceId: UUID, direction: SplitTree.NewDirection) -> Bool { - guard let tab = tabs.first(where: { $0.id == tabId }) else { return false } - return tab.newSplit(from: surfaceId, direction: direction) != nil + func newSplit(tabId: UUID, surfaceId: UUID, direction: SplitTree.NewDirection) -> UUID? { + guard let tab = tabs.first(where: { $0.id == tabId }) else { return nil } + return tab.newSplit(from: surfaceId, direction: direction)?.id } func moveSplitFocus(tabId: UUID, surfaceId: UUID, direction: SplitTree.FocusDirection) -> Bool { diff --git a/Sources/TerminalController.swift b/Sources/TerminalController.swift index 835c3bc0..51ff6a42 100644 --- a/Sources/TerminalController.swift +++ b/Sources/TerminalController.swift @@ -236,7 +236,7 @@ class TerminalController { ping - Check if server is running list_tabs - List all tabs with IDs new_tab - Create a new tab - new_split - Split focused surface (left/right/up/down) + new_split [panel] - Split surface (left/right/up/down), optionally specify panel list_surfaces [tab] - List surfaces for tab (current tab if omitted) focus_surface - Focus surface by ID or index (current tab) close_tab - Close tab by ID @@ -311,24 +311,51 @@ class TerminalController { return "OK \(newTabId?.uuidString ?? "unknown")" } - private func newSplit(_ directionArg: String) -> String { + private func newSplit(_ args: String) -> String { guard let tabManager = tabManager else { return "ERROR: TabManager not available" } - let trimmed = directionArg.trimmingCharacters(in: .whitespacesAndNewlines) - guard let direction = parseSplitDirection(trimmed) else { + let trimmed = args.trimmingCharacters(in: .whitespacesAndNewlines) + let parts = trimmed.split(separator: " ", maxSplits: 1).map(String.init) + guard !parts.isEmpty else { return "ERROR: Invalid direction. Use left, right, up, or down." } - var success = false + let directionArg = parts[0] + let panelArg = parts.count > 1 ? parts[1] : "" + + guard let direction = parseSplitDirection(directionArg) else { + return "ERROR: Invalid direction. Use left, right, up, or down." + } + + var result = "ERROR: Failed to create split" DispatchQueue.main.sync { guard let tabId = tabManager.selectedTabId, - let tab = tabManager.tabs.first(where: { $0.id == tabId }), - let surfaceId = tab.focusedSurfaceId else { + let tab = tabManager.tabs.first(where: { $0.id == tabId }) else { return } - success = tabManager.newSplit(tabId: tabId, surfaceId: surfaceId, direction: direction) + + // If panel arg provided, resolve it; otherwise use focused surface + let surfaceId: UUID? + if !panelArg.isEmpty { + surfaceId = resolveSurfaceId(from: panelArg, tab: tab) + if surfaceId == nil { + result = "ERROR: Panel not found" + return + } + } else { + surfaceId = tab.focusedSurfaceId + } + + guard let targetSurface = surfaceId else { + result = "ERROR: No surface to split" + return + } + + if let newPanelId = tabManager.newSplit(tabId: tabId, surfaceId: targetSurface, direction: direction) { + result = "OK \(newPanelId.uuidString)" + } } - return success ? "OK" : "ERROR: Failed to create split" + return result } private func listSurfaces(_ tabArg: String) -> String {