diff --git a/Sources/ContentView.swift b/Sources/ContentView.swift index 9393bdf3..e3b8c37c 100644 --- a/Sources/ContentView.swift +++ b/Sources/ContentView.swift @@ -6994,7 +6994,12 @@ private struct TabItemView: View { private func openPullRequestLink(_ url: URL) { updateSelection() if openSidebarPullRequestLinksInCmuxBrowser { - if tabManager.openBrowser(url: url, insertAtEnd: true) == nil { + if tabManager.openBrowser( + inWorkspace: tab.id, + url: url, + preferSplitRight: true, + insertAtEnd: true + ) == nil { NSWorkspace.shared.open(url) } return diff --git a/Sources/TabManager.swift b/Sources/TabManager.swift index 345c08d1..8efe9677 100644 --- a/Sources/TabManager.swift +++ b/Sources/TabManager.swift @@ -1940,19 +1940,70 @@ class TabManager: ObservableObject { return tab.browserPanel(for: panelId) } + /// Open a browser in a specific workspace, optionally preferring a split-right layout. + @discardableResult + func openBrowser( + inWorkspace tabId: UUID, + url: URL? = nil, + preferSplitRight: Bool = false, + insertAtEnd: Bool = false + ) -> UUID? { + guard let workspace = tabs.first(where: { $0.id == tabId }) else { return nil } + if selectedTabId != tabId { + selectedTabId = tabId + } + + if preferSplitRight { + let splitSourcePanelId: UUID? = { + if let focusedPanelId = workspace.focusedPanelId, + workspace.panels[focusedPanelId] != nil { + return focusedPanelId + } + if let rememberedPanelId = lastFocusedPanelByTab[tabId], + workspace.panels[rememberedPanelId] != nil { + return rememberedPanelId + } + if let orderedPanelId = workspace.sidebarOrderedPanelIds().first(where: { workspace.panels[$0] != nil }) { + return orderedPanelId + } + return workspace.panels.keys.sorted { $0.uuidString < $1.uuidString }.first + }() + + if let splitSourcePanelId, + let browserPanel = workspace.newBrowserSplit( + from: splitSourcePanelId, + orientation: .horizontal, + url: url, + focus: true + ) { + rememberFocusedSurface(tabId: tabId, surfaceId: browserPanel.id) + return browserPanel.id + } + } + + guard let paneId = workspace.bonsplitController.focusedPaneId ?? workspace.bonsplitController.allPaneIds.first, + let browserPanel = workspace.newBrowserSurface( + inPane: paneId, + url: url, + focus: true, + insertAtEnd: insertAtEnd + ) else { + return nil + } + rememberFocusedSurface(tabId: tabId, surfaceId: browserPanel.id) + return browserPanel.id + } + /// Open a browser in the currently focused pane (as a new surface) @discardableResult func openBrowser(url: URL? = nil, insertAtEnd: Bool = false) -> UUID? { - guard let tabId = selectedTabId, - let tab = tabs.first(where: { $0.id == tabId }), - let focusedPaneId = tab.bonsplitController.focusedPaneId else { return nil } - let panel = tab.newBrowserSurface( - inPane: focusedPaneId, + guard let tabId = selectedTabId else { return nil } + return openBrowser( + inWorkspace: tabId, url: url, - focus: true, + preferSplitRight: false, insertAtEnd: insertAtEnd ) - return panel?.id } /// Reopen the most recently closed browser panel (Cmd+Shift+T). diff --git a/cmuxTests/CmuxWebViewKeyEquivalentTests.swift b/cmuxTests/CmuxWebViewKeyEquivalentTests.swift index 59bcab74..70a06646 100644 --- a/cmuxTests/CmuxWebViewKeyEquivalentTests.swift +++ b/cmuxTests/CmuxWebViewKeyEquivalentTests.swift @@ -2868,6 +2868,54 @@ final class TabManagerSurfaceCreationTests: XCTestCase { ) XCTAssertEqual(workspace.focusedPanelId, browserPanelId, "Expected opened browser surface to be focused") } + + func testOpenBrowserInWorkspaceSplitRightSelectsTargetWorkspaceAndCreatesSplit() { + let manager = TabManager() + guard let initialWorkspace = manager.selectedWorkspace else { + XCTFail("Expected initial selected workspace") + return + } + guard let url = URL(string: "https://example.com/pull/123") else { + XCTFail("Expected test URL to be valid") + return + } + + let targetWorkspace = manager.addWorkspace(select: false) + manager.selectWorkspace(initialWorkspace) + let initialPaneCount = targetWorkspace.bonsplitController.allPaneIds.count + let initialPanelCount = targetWorkspace.panels.count + + guard let browserPanelId = manager.openBrowser( + inWorkspace: targetWorkspace.id, + url: url, + preferSplitRight: true, + insertAtEnd: true + ) else { + XCTFail("Expected browser panel to be created in target workspace") + return + } + + XCTAssertEqual(manager.selectedTabId, targetWorkspace.id, "Expected target workspace to become selected") + XCTAssertEqual( + targetWorkspace.bonsplitController.allPaneIds.count, + initialPaneCount + 1, + "Expected split-right browser open to create a new pane" + ) + XCTAssertEqual( + targetWorkspace.panels.count, + initialPanelCount + 1, + "Expected browser panel count to increase by one" + ) + XCTAssertEqual( + targetWorkspace.focusedPanelId, + browserPanelId, + "Expected created browser panel to be focused in target workspace" + ) + XCTAssertTrue( + targetWorkspace.panels[browserPanelId] is BrowserPanel, + "Expected created panel to be a browser panel" + ) + } } @MainActor