Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b77d7c2
Add titlebar visibility options
lawrencecchen Mar 13, 2026
ca6f83f
Refine hidden titlebar behavior
lawrencecchen Mar 13, 2026
cdcfa19
Remove hidden titlebar safe-area gap
lawrencecchen Mar 13, 2026
c8d561c
Add Bonsplit hidden-titlebar drag regression test
lawrencecchen Mar 13, 2026
7385a01
Fix hidden-titlebar pane tab bar controls
lawrencecchen Mar 13, 2026
d5cf95a
Tighten hidden titlebar pane tab layout
lawrencecchen Mar 13, 2026
6b281dc
Remove hidden titlebar top gap
lawrencecchen Mar 13, 2026
3e75be2
Fix hidden-titlebar tab drag host
lawrencecchen Mar 13, 2026
cf3a132
Fix hidden-titlebar pane drag regression
lawrencecchen Mar 13, 2026
6244e49
Add hidden-titlebar top-gap UI test
lawrencecchen Mar 13, 2026
d7d6c60
Remove titlebar accessories when hidden
lawrencecchen Mar 13, 2026
945881b
Use non-movable pane tab bar host
lawrencecchen Mar 13, 2026
cc51646
Underlap hidden workspace content
lawrencecchen Mar 13, 2026
dc394ad
Strengthen hidden titlebar UI regressions
lawrencecchen Mar 13, 2026
9ecefc5
Remove Bonsplit hidden-titlebar inset
lawrencecchen Mar 13, 2026
239ec1d
Wait for Bonsplit UI test setup readiness
lawrencecchen Mar 13, 2026
a82fa63
Add hidden titlebar chrome UI regressions
lawrencecchen Mar 13, 2026
18d2d5f
Fix hidden titlebar chrome regressions
lawrencecchen Mar 13, 2026
5cd4b30
Assert tab drag does not move the window
lawrencecchen Mar 13, 2026
67f2bda
Add raw mouse Bonsplit drag UI regression
lawrencecchen Mar 13, 2026
afd2d21
Fix hidden-titlebar Bonsplit tab drags
lawrencecchen Mar 13, 2026
278a2ff
Stabilize Bonsplit drag UI tests
lawrencecchen Mar 13, 2026
5c42da4
Add stronger Bonsplit drag reorder regression
lawrencecchen Mar 13, 2026
f1e0abe
Fix hidden-titlebar Bonsplit tab reorder drops
lawrencecchen Mar 13, 2026
8d96c97
Add stronger Bonsplit drag and titlebar regressions
lawrencecchen Mar 13, 2026
ae0a4e3
Fix hidden-titlebar traffic lights and Bonsplit drops
lawrencecchen Mar 13, 2026
b61698c
test: cover hidden-titlebar collapsed-sidebar controls
lawrencecchen Mar 15, 2026
87ee59f
fix: collapse hidden-titlebar controls with hidden sidebar
lawrencecchen Mar 15, 2026
39d8cc2
test: cover hidden-titlebar sidebar traffic-light gap
lawrencecchen Mar 15, 2026
3a41872
fix: align hidden-titlebar tabs with the sidebar edge
lawrencecchen Mar 15, 2026
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
12 changes: 10 additions & 2 deletions GhosttyTabs.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
A5001002 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5001012 /* ContentView.swift */; };
E62155868BB29FEB5DAAAF25 /* SidebarSelectionState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AD52285508B1D6A9875E7B3 /* SidebarSelectionState.swift */; };
B9000018A1B2C3D4E5F60719 /* WindowDragHandleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9000017A1B2C3D4E5F60719 /* WindowDragHandleView.swift */; };
C9A10001A1B2C3D4E5F60719 /* TitlebarVisibilitySettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9A10002A1B2C3D4E5F60719 /* TitlebarVisibilitySettings.swift */; };
A5001003 /* TabManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5001013 /* TabManager.swift */; };
A5001004 /* GhosttyConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5001014 /* GhosttyConfig.swift */; };
A5001005 /* GhosttyTerminalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5001015 /* GhosttyTerminalView.swift */; };
Expand Down Expand Up @@ -73,6 +74,7 @@
84E00D47E4584162AE53BC8D /* xterm-ghostty in Resources */ = {isa = PBXBuildFile; fileRef = B2E7294509CC42FE9191870E /* xterm-ghostty */; };
A5002000 /* THIRD_PARTY_LICENSES.md in Resources */ = {isa = PBXBuildFile; fileRef = A5002001 /* THIRD_PARTY_LICENSES.md */; };
B9000012A1B2C3D4E5F60719 /* AutomationSocketUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9000011A1B2C3D4E5F60719 /* AutomationSocketUITests.swift */; };
D4A1B2C3D4E5F60718000002 /* BonsplitTabDragUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4A1B2C3D4E5F60718000001 /* BonsplitTabDragUITests.swift */; };
B8F266236A1A3D9A45BD840F /* SidebarResizeUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 818DBCD4AB69EB72573E8138 /* SidebarResizeUITests.swift */; };
B8F266246A1A3D9A45BD840F /* SidebarHelpMenuUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8F266256A1A3D9A45BD840F /* SidebarHelpMenuUITests.swift */; };
C0B4D9B0A1B2C3D4E5F60718 /* UpdatePillUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0B4D9B1A1B2C3D4E5F60718 /* UpdatePillUITests.swift */; };
Expand Down Expand Up @@ -158,6 +160,7 @@
A5001012 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
9AD52285508B1D6A9875E7B3 /* SidebarSelectionState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarSelectionState.swift; sourceTree = "<group>"; };
B9000017A1B2C3D4E5F60719 /* WindowDragHandleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowDragHandleView.swift; sourceTree = "<group>"; };
C9A10002A1B2C3D4E5F60719 /* TitlebarVisibilitySettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitlebarVisibilitySettings.swift; sourceTree = "<group>"; };
A5001013 /* TabManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabManager.swift; sourceTree = "<group>"; };
A5001014 /* GhosttyConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GhosttyConfig.swift; sourceTree = "<group>"; };
A5001015 /* GhosttyTerminalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GhosttyTerminalView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -209,8 +212,9 @@
A5001223 /* UpdateLogStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Update/UpdateLogStore.swift; sourceTree = "<group>"; };
A5001241 /* WindowDecorationsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowDecorationsController.swift; sourceTree = "<group>"; };
A5001611 /* SessionPersistence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionPersistence.swift; sourceTree = "<group>"; };
818DBCD4AB69EB72573E8138 /* SidebarResizeUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarResizeUITests.swift; sourceTree = "<group>"; };
B8F266256A1A3D9A45BD840F /* SidebarHelpMenuUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarHelpMenuUITests.swift; sourceTree = "<group>"; };
818DBCD4AB69EB72573E8138 /* SidebarResizeUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarResizeUITests.swift; sourceTree = "<group>"; };
D4A1B2C3D4E5F60718000001 /* BonsplitTabDragUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BonsplitTabDragUITests.swift; sourceTree = "<group>"; };
B8F266256A1A3D9A45BD840F /* SidebarHelpMenuUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarHelpMenuUITests.swift; sourceTree = "<group>"; };
C0B4D9B1A1B2C3D4E5F60718 /* UpdatePillUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdatePillUITests.swift; sourceTree = "<group>"; };
A5001101 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
IC000002 /* AppIcon.icon */ = {isa = PBXFileReference; lastKnownFileType = folder; path = AppIcon.icon; sourceTree = "<group>"; };
Expand Down Expand Up @@ -357,6 +361,7 @@
A5001012 /* ContentView.swift */,
9AD52285508B1D6A9875E7B3 /* SidebarSelectionState.swift */,
B9000017A1B2C3D4E5F60719 /* WindowDragHandleView.swift */,
C9A10002A1B2C3D4E5F60719 /* TitlebarVisibilitySettings.swift */,
A50012F0 /* Backport.swift */,
A50012F2 /* KeyboardShortcutSettings.swift */,
A50012F4 /* KeyboardLayout.swift */,
Expand Down Expand Up @@ -445,6 +450,7 @@
isa = PBXGroup;
children = (
B9000011A1B2C3D4E5F60719 /* AutomationSocketUITests.swift */,
D4A1B2C3D4E5F60718000001 /* BonsplitTabDragUITests.swift */,
B9000013A1B2C3D4E5F60719 /* JumpToUnreadUITests.swift */,
B9000022A1B2C3D4E5F60719 /* CloseWorkspaceCmdDUITests.swift */,
B9000019A1B2C3D4E5F60719 /* CloseWorkspaceConfirmDialogUITests.swift */,
Expand Down Expand Up @@ -628,6 +634,7 @@
A5001002 /* ContentView.swift in Sources */,
E62155868BB29FEB5DAAAF25 /* SidebarSelectionState.swift in Sources */,
B9000018A1B2C3D4E5F60719 /* WindowDragHandleView.swift in Sources */,
C9A10001A1B2C3D4E5F60719 /* TitlebarVisibilitySettings.swift in Sources */,
A50012F1 /* Backport.swift in Sources */,
A50012F3 /* KeyboardShortcutSettings.swift in Sources */,
A50012F5 /* KeyboardLayout.swift in Sources */,
Expand Down Expand Up @@ -684,6 +691,7 @@
buildActionMask = 2147483647;
files = (
B9000012A1B2C3D4E5F60719 /* AutomationSocketUITests.swift in Sources */,
D4A1B2C3D4E5F60718000002 /* BonsplitTabDragUITests.swift in Sources */,
B9000014A1B2C3D4E5F60719 /* JumpToUnreadUITests.swift in Sources */,
B900001AA1B2C3D4E5F60719 /* CloseWorkspaceConfirmDialogUITests.swift in Sources */,
B9000023A1B2C3D4E5F60719 /* CloseWorkspaceCmdDUITests.swift in Sources */,
Expand Down
187 changes: 187 additions & 0 deletions Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -73093,6 +73093,193 @@
}
}
}
},
"settings.app.showWorkspaceTitlebar": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Show Workspace Title Bar"
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "ワークスペースのタイトルバーを表示"
}
}
}
},
"settings.app.showWorkspaceTitlebar.subtitleOff": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Hide the folder/title strip and drag from empty space in the top pane tab bar."
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "フォルダとタイトルの帯を隠し、上部のペインタブバーの空き領域からウィンドウをドラッグできます。"
}
}
}
},
"settings.app.showWorkspaceTitlebar.subtitleOn": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Show the folder and active title above pane tabs."
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "ペインタブの上にフォルダ名と現在のタイトルを表示します。"
}
}
}
},
"settings.app.titlebarControls": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Titlebar Controls"
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "タイトルバーのコントロール"
}
}
}
},
"settings.app.titlebarControls.always": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Always Visible"
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "常に表示"
}
}
}
},
"settings.app.titlebarControls.hover": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Show on Hover"
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "ホバー時に表示"
}
}
}
},
"settings.app.titlebarControls.subtitleAlways": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Keep the sidebar, notifications, and new workspace buttons visible."
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "サイドバー、通知、新規ワークスペースのボタンを常に表示します。"
}
}
}
},
"settings.app.titlebarControls.subtitleHover": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Hide titlebar buttons until the pointer reaches them."
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "ポインタが近づくまでタイトルバーのボタンを隠します。"
}
}
}
},
"settings.app.paneTabBarControls": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Pane Tab Bar Controls"
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "ペインタブバーのコントロール"
}
}
}
},
"settings.app.paneTabBarControls.subtitleAlways": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Keep the pane tab bar's new tab and split buttons visible."
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "ペインタブバーの新規タブボタンと分割ボタンを常に表示します。"
}
}
}
},
"settings.app.paneTabBarControls.subtitleHover": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Hide the pane tab bar's new tab and split buttons until you hover the bar."
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "ペインタブバーにホバーするまで、新規タブボタンと分割ボタンを隠します。"
}
}
}
Comment on lines +73233 to +73282
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check how paneTabBarControls mode labels are resolved in the codebase
# Looking for whether it shares titlebarControls labels or needs its own

# Search for paneTabBarControls localization key usage
rg -n "paneTabBarControls" --type swift -C 3

# Search for how the visibility mode displayName is implemented
ast-grep --pattern 'displayName'

Repository: manaflow-ai/cmux

Length of output: 8792


🏁 Script executed:

rg -n "enum ChromeControlsVisibilityMode" -A 20 --type swift

Repository: manaflow-ai/cmux

Length of output: 1632


🏁 Script executed:

rg -n "extension ChromeControlsVisibilityMode" -A 15 --type swift

Repository: manaflow-ai/cmux

Length of output: 1056


Add separate mode display name keys for paneTabBarControls or explicitly document intentional key sharing.

The paneTabBarControls picker uses ChromeControlsVisibilityMode.displayName, which hardcodes localization keys from settings.app.titlebarControls.always and settings.app.titlebarControls.hover (lines 3047-3049 in cmuxApp.swift). While both controls share the same enum, this creates implicit coupling.

Consider either:

  1. Adding separate settings.app.paneTabBarControls.always and settings.app.paneTabBarControls.hover keys to the localization file for independent control, or
  2. Refactoring the displayName implementation to make the key sharing explicit and documented in code.

Currently, changes to titlebar mode labels would unintentionally affect pane tab bar mode labels.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Resources/Localizable.xcstrings` around lines 73233 - 73282, The
paneTabBarControls picker is reusing ChromeControlsVisibilityMode.displayName
keys (from cmuxApp.swift) which couples pane labels to titlebar labels; add
explicit localization keys or make the sharing explicit: either add
settings.app.paneTabBarControls.always and settings.app.paneTabBarControls.hover
entries to Resources/Localizable.xcstrings and update the UI to use those keys
for paneTabBarControls, or modify ChromeControlsVisibilityMode.displayName (or
the code that maps modes for paneTabBarControls in cmuxApp.swift) to return the
titlebar key intentionally with a clear comment and/or a dedicated mapping
function so changes to titlebar labels won’t silently affect pane labels.

}
}
}
Loading