From aa222dbc0d6d23c23d4c6dd22f9a4b06aa450ef3 Mon Sep 17 00:00:00 2001 From: Lawrence Chen <54008264+lawrencecchen@users.noreply.github.com> Date: Tue, 24 Feb 2026 14:32:56 -0800 Subject: [PATCH] Sidebar double-click appends workspace to end --- Sources/ContentView.swift | 2 +- Sources/TabManager.swift | 12 +++-- cmuxTests/CmuxWebViewKeyEquivalentTests.swift | 53 +++++++++++++++++++ 3 files changed, 62 insertions(+), 5 deletions(-) diff --git a/Sources/ContentView.swift b/Sources/ContentView.swift index 495e218a..9dbaec0b 100644 --- a/Sources/ContentView.swift +++ b/Sources/ContentView.swift @@ -5903,7 +5903,7 @@ private struct SidebarEmptyArea: View { .contentShape(Rectangle()) .frame(maxWidth: .infinity, maxHeight: .infinity) .onTapGesture(count: 2) { - tabManager.addTab() + tabManager.addWorkspace(placementOverride: .end) if let selectedId = tabManager.selectedTabId { selectedTabIds = [selectedId] lastSidebarSelectionIndex = tabManager.tabs.firstIndex { $0.id == selectedId } diff --git a/Sources/TabManager.swift b/Sources/TabManager.swift index 5f0a5482..901b2587 100644 --- a/Sources/TabManager.swift +++ b/Sources/TabManager.swift @@ -758,7 +758,11 @@ class TabManager: ObservableObject { } @discardableResult - func addWorkspace(workingDirectory overrideWorkingDirectory: String? = nil, select: Bool = true) -> Workspace { + func addWorkspace( + workingDirectory overrideWorkingDirectory: String? = nil, + select: Bool = true, + placementOverride: NewWorkspacePlacement? = nil + ) -> Workspace { sentryBreadcrumb("workspace.create", data: ["tabCount": tabs.count + 1]) let workingDirectory = normalizedWorkingDirectory(overrideWorkingDirectory) ?? preferredWorkingDirectoryForNewTab() let inheritedConfig = inheritedTerminalConfigForNewWorkspace() @@ -771,7 +775,7 @@ class TabManager: ObservableObject { configTemplate: inheritedConfig ) wireClosedBrowserTracking(for: newWorkspace) - let insertIndex = newTabInsertIndex() + let insertIndex = newTabInsertIndex(placementOverride: placementOverride) if insertIndex >= 0 && insertIndex <= tabs.count { tabs.insert(newWorkspace, at: insertIndex) } else { @@ -836,8 +840,8 @@ class TabManager: ObservableObject { return trimmed.isEmpty ? nil : normalized } - private func newTabInsertIndex() -> Int { - let placement = WorkspacePlacementSettings.current() + private func newTabInsertIndex(placementOverride: NewWorkspacePlacement? = nil) -> Int { + let placement = placementOverride ?? WorkspacePlacementSettings.current() let pinnedCount = tabs.filter { $0.isPinned }.count let selectedIndex = selectedTabId.flatMap { tabId in tabs.firstIndex(where: { $0.id == tabId }) diff --git a/cmuxTests/CmuxWebViewKeyEquivalentTests.swift b/cmuxTests/CmuxWebViewKeyEquivalentTests.swift index 132f2374..7292f8ad 100644 --- a/cmuxTests/CmuxWebViewKeyEquivalentTests.swift +++ b/cmuxTests/CmuxWebViewKeyEquivalentTests.swift @@ -2214,6 +2214,59 @@ final class WorkspacePlacementSettingsTests: XCTestCase { } } +@MainActor +final class WorkspaceCreationPlacementTests: XCTestCase { + func testAddWorkspaceDefaultPlacementMatchesCurrentSetting() { + let currentPlacement = WorkspacePlacementSettings.current() + + let defaultManager = makeManagerWithThreeWorkspaces() + let defaultBaselineOrder = defaultManager.tabs.map(\.id) + let defaultInserted = defaultManager.addWorkspace() + guard let defaultInsertedIndex = defaultManager.tabs.firstIndex(where: { $0.id == defaultInserted.id }) else { + XCTFail("Expected inserted workspace in tab list") + return + } + XCTAssertEqual(defaultManager.tabs.map(\.id).filter { $0 != defaultInserted.id }, defaultBaselineOrder) + + let explicitManager = makeManagerWithThreeWorkspaces() + let explicitBaselineOrder = explicitManager.tabs.map(\.id) + let explicitInserted = explicitManager.addWorkspace(placementOverride: currentPlacement) + guard let explicitInsertedIndex = explicitManager.tabs.firstIndex(where: { $0.id == explicitInserted.id }) else { + XCTFail("Expected inserted workspace in tab list") + return + } + XCTAssertEqual(explicitManager.tabs.map(\.id).filter { $0 != explicitInserted.id }, explicitBaselineOrder) + XCTAssertEqual(defaultInsertedIndex, explicitInsertedIndex) + } + + func testAddWorkspaceEndOverrideAlwaysAppends() { + let manager = makeManagerWithThreeWorkspaces() + let baselineCount = manager.tabs.count + guard baselineCount >= 3 else { + XCTFail("Expected at least three workspaces for placement regression test") + return + } + + let inserted = manager.addWorkspace(placementOverride: .end) + guard let insertedIndex = manager.tabs.firstIndex(where: { $0.id == inserted.id }) else { + XCTFail("Expected inserted workspace in tab list") + return + } + + XCTAssertEqual(insertedIndex, baselineCount) + } + + private func makeManagerWithThreeWorkspaces() -> TabManager { + let manager = TabManager() + _ = manager.addWorkspace() + _ = manager.addWorkspace() + if let first = manager.tabs.first { + manager.selectWorkspace(first) + } + return manager + } +} + final class WorkspaceTabColorSettingsTests: XCTestCase { func testNormalizedHexAcceptsAndNormalizesValidInput() { XCTAssertEqual(WorkspaceTabColorSettings.normalizedHex("#abc123"), "#ABC123")