Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 47 additions & 11 deletions Sources/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,22 @@ struct SidebarWorkspaceRowBackgroundStyle {
static let clear = Self(color: nil, opacity: 0)
}

func sidebarWorkspaceRowExplicitRailNSColor(
activeTabIndicatorStyle: SidebarActiveTabIndicatorStyle,
customColorHex: String?,
colorScheme: ColorScheme
) -> NSColor? {
guard activeTabIndicatorStyle == .leftRail,
let customColorHex else {
return nil
}
return WorkspaceTabColorSettings.displayNSColor(
hex: customColorHex,
colorScheme: colorScheme,
forceBright: true
)
}

func sidebarWorkspaceRowBackgroundStyle(
activeTabIndicatorStyle: SidebarActiveTabIndicatorStyle,
isActive: Bool,
Expand All @@ -223,24 +239,15 @@ func sidebarWorkspaceRowBackgroundStyle(
forceBright: activeTabIndicatorStyle == .leftRail
)
}
let selectedCustomBackground = customColorHex.flatMap {
sidebarSelectedWorkspaceCustomBackgroundNSColor(hex: $0, colorScheme: colorScheme)
}

switch activeTabIndicatorStyle {
case .leftRail:
if isActive {
return SidebarWorkspaceRowBackgroundStyle(
color: selectedCustomBackground ?? selectedBackground,
color: selectedBackground,
opacity: 1
)
}
if let customBackground {
return SidebarWorkspaceRowBackgroundStyle(
color: customBackground,
opacity: isMultiSelected ? 0.35 : 0.7

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused customBackground computation in leftRail branch

Low Severity

The customBackground variable is computed for all activeTabIndicatorStyle values but is now only consumed in the solidFill branch. In the leftRail branch it's unused dead computation. Additionally, the forceBright: activeTabIndicatorStyle == .leftRail expression is misleading — it evaluates to true only in the path that never reads customBackground, and is always false when the variable is actually used, making it functionally equivalent to forceBright: false.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit b32086f. Configure here.

)
}
if isMultiSelected {
return SidebarWorkspaceRowBackgroundStyle(color: accentBackground, opacity: 0.25)
}
Expand All @@ -249,7 +256,7 @@ func sidebarWorkspaceRowBackgroundStyle(
case .solidFill:
if isActive {
return SidebarWorkspaceRowBackgroundStyle(
color: selectedCustomBackground ?? selectedBackground,
color: selectedBackground,
opacity: 1
)
}
Expand Down Expand Up @@ -13073,6 +13080,10 @@ private struct TabItemView: View, Equatable {
.semibold
}

private var showsLeadingRail: Bool {
explicitRailColor != nil
}

private var activeBorderLineWidth: CGFloat {
switch activeTabIndicatorStyle {
case .leftRail:
Expand Down Expand Up @@ -13501,6 +13512,16 @@ private struct TabItemView: View, Equatable {
RoundedRectangle(cornerRadius: 6)
.strokeBorder(activeBorderColor, lineWidth: activeBorderLineWidth)
}
.overlay(alignment: .leading) {
if showsLeadingRail {
Capsule(style: .continuous)
.fill(railColor)
.frame(width: 3)
.padding(.leading, 4)
.padding(.vertical, 5)
.offset(x: -1)
}
}
)
.padding(.horizontal, 6)
.background {
Expand Down Expand Up @@ -13943,6 +13964,21 @@ private struct TabItemView: View, Equatable {
return Color(nsColor: color).opacity(style.opacity)
}

private var railColor: Color {
explicitRailColor ?? .clear
}

private var explicitRailColor: Color? {
guard let railColor = sidebarWorkspaceRowExplicitRailNSColor(
activeTabIndicatorStyle: activeTabIndicatorStyle,
customColorHex: workspaceSnapshot.customColorHex,
colorScheme: colorScheme
) else {
return nil
}
return Color(nsColor: railColor).opacity(0.95)
}
Comment on lines +13972 to +13980

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Local binding shadows the outer railColor property

Inside explicitRailColor, the guard let railColor = ... binding is the same name as the struct-level railColor: Color computed property. Swift resolves this correctly (the guard's binding is NSColor, the outer property is Color), but it silently shadows the outer name within the guard's scope, which can confuse readers. Consider renaming the local binding to nsColor or resolvedNSColor for clarity.

Suggested change
guard let railColor = sidebarWorkspaceRowExplicitRailNSColor(
activeTabIndicatorStyle: activeTabIndicatorStyle,
customColorHex: workspaceSnapshot.customColorHex,
colorScheme: colorScheme
) else {
return nil
}
return Color(nsColor: railColor).opacity(0.95)
}
guard let nsColor = sidebarWorkspaceRowExplicitRailNSColor(
activeTabIndicatorStyle: activeTabIndicatorStyle,
customColorHex: workspaceSnapshot.customColorHex,
colorScheme: colorScheme
) else {
return nil
}
return Color(nsColor: nsColor).opacity(0.95)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!


private func tabColorSwatchColor(for hex: String) -> NSColor {
WorkspaceTabColorSettings.displayNSColor(
hex: hex,
Expand Down
80 changes: 76 additions & 4 deletions cmuxTests/WorkspaceUnitTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ final class SidebarSelectedWorkspaceColorTests: XCTestCase {
}

@MainActor
func testSetTabColorFeedsSelectedSolidFillSidebarBackground() {
func testSolidFillKeepsSelectedBackgroundForActiveCustomColoredWorkspaceRow() {
let manager = TabManager()
guard let workspace = manager.tabs.first else {
XCTFail("Expected TabManager to initialise with a workspace")
Expand All @@ -87,13 +87,16 @@ final class SidebarSelectedWorkspaceColorTests: XCTestCase {
sidebarSelectionColorHex: nil
)

XCTAssertEqual(background.color?.hexString(), "#C0392B")
XCTAssertEqual(
background.color?.hexString(),
sidebarSelectedWorkspaceBackgroundNSColor(for: .light).hexString()
)
XCTAssertEqual(background.opacity, 1.0, accuracy: 0.001)
withExtendedLifetime(cancellable) {}
}

@MainActor
func testSetTabColorFeedsSelectedDefaultSidebarBackground() {
func testLeftRailKeepsSelectedBackgroundForActiveCustomColoredWorkspaceRow() {
let manager = TabManager()
guard let workspace = manager.tabs.first else {
XCTFail("Expected TabManager to initialise with a workspace")
Expand All @@ -119,10 +122,79 @@ final class SidebarSelectedWorkspaceColorTests: XCTestCase {
sidebarSelectionColorHex: nil
)

XCTAssertEqual(background.color?.hexString(), "#C0392B")
XCTAssertEqual(
background.color?.hexString(),
sidebarSelectedWorkspaceBackgroundNSColor(for: .light).hexString()
)
XCTAssertEqual(background.opacity, 1.0, accuracy: 0.001)
withExtendedLifetime(cancellable) {}
}

@MainActor
func testLeftRailLeavesInactiveCustomColoredWorkspaceRowTransparent() {
let manager = TabManager()
guard let workspace = manager.tabs.first else {
XCTFail("Expected TabManager to initialise with a workspace")
return
}

manager.setTabColor(tabId: workspace.id, color: "#C0392B")

let background = sidebarWorkspaceRowBackgroundStyle(
activeTabIndicatorStyle: .leftRail,
isActive: false,
isMultiSelected: false,
customColorHex: workspace.customColor,
colorScheme: .light,
sidebarSelectionColorHex: nil
)

XCTAssertNil(background.color)
XCTAssertEqual(background.opacity, 0, accuracy: 0.001)
}

@MainActor
func testLeftRailResolvesExplicitRailColorForCustomColoredWorkspaceRow() {
let manager = TabManager()
guard let workspace = manager.tabs.first else {
XCTFail("Expected TabManager to initialise with a workspace")
return
}

manager.setTabColor(tabId: workspace.id, color: "#C0392B")

let railColor = sidebarWorkspaceRowExplicitRailNSColor(
activeTabIndicatorStyle: .leftRail,
customColorHex: workspace.customColor,
colorScheme: .light
)

XCTAssertNotNil(railColor)
XCTAssertEqual(railColor?.hexString(), "#C0392B")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test expects raw hex but function applies color brightening

Medium Severity

The test testLeftRailResolvesExplicitRailColorForCustomColoredWorkspaceRow asserts that railColor?.hexString() equals "#C0392B", but sidebarWorkspaceRowExplicitRailNSColor calls WorkspaceTabColorSettings.displayNSColor with forceBright: true. This triggers brightenedForDarkAppearance, which boosts brightness and saturation of the input color, producing a hex value different from the raw input "#C0392B". This test will fail.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit b32086f. Configure here.

}

@MainActor
func testSolidFillUsesInactiveCustomWorkspaceColorAsBackground() {
let manager = TabManager()
guard let workspace = manager.tabs.first else {
XCTFail("Expected TabManager to initialise with a workspace")
return
}

manager.setTabColor(tabId: workspace.id, color: "#C0392B")

let background = sidebarWorkspaceRowBackgroundStyle(
activeTabIndicatorStyle: .solidFill,
isActive: false,
isMultiSelected: false,
customColorHex: workspace.customColor,
colorScheme: .light,
sidebarSelectionColorHex: nil
)

XCTAssertEqual(background.color?.hexString(), "#C0392B")
XCTAssertEqual(background.opacity, 0.7, accuracy: 0.001)
}
}


Expand Down
Loading