* fix: avoid NSTextView tracking loop in omnibar mouseDown (#917)
Replace the synthetic mouseUp timeout workaround with direct cursor
positioning via NSTextView.characterIndexForInsertion(at:). The previous
approach posted a fake mouseUp event via NSApp.postEvent after 3 seconds,
but the NSTextView tracking loop does not always dequeue events from the
application event queue when stuck in an infinite
NSTextLayoutManager.enumerateTextLayoutFragments cycle, so the hang
persisted.
The new approach bypasses super.mouseDown entirely when the field editor
is already active, positioning the cursor (or extending the selection
with Shift+click) without entering the tracking loop. Drag-to-select is
not supported in this code path, but for a single-line omnibar this is
an acceptable trade-off.
* fix: handle double-click, UTF-16 length, and shift-click anchor
Address review feedback:
- Forward double/triple-click events to editor.mouseDown(with:) to
preserve word and line selection without entering NSTextField's
tracking loop
- Use (editor.string as NSString).length instead of String.count for
NSRange clamping (NSRange uses UTF-16 indices)
- Track shift-click anchor independently via shiftClickAnchor property
to correctly handle bidirectional selection extension
* fix: reset shiftClickAnchor on keyDown to prevent stale anchor
Clear the shift-click selection anchor whenever a key is pressed, so
that keyboard navigation (arrow keys, Shift+arrow, Home/End, etc.)
properly invalidates the mouse-originated anchor. A subsequent
Shift+click will then use the current selection position as anchor
instead of a stale value from a prior mouse interaction.
* fix: reset shiftClickAnchor in performKeyEquivalent and on re-focus
Key equivalents (Cmd+A, Cmd+V, etc.) bypass keyDown and go through
performKeyEquivalent, so the anchor must also be cleared there.
Similarly, re-focusing the field (currentEditor() == nil path) should
reset the anchor since selectAll changes the selection state.
JavaScript-based find using TreeWalker + <mark> highlights with
match counter, next/previous navigation, and drag-to-corner overlay
matching the existing terminal find bar.
- BrowserFindJavaScript: JS generation for search/next/prev/clear
- BrowserSearchOverlay: SwiftUI overlay with IME-safe onSubmit
- BrowserSearchState: Observable state (needle/selected/total)
- TabManager routing: Cmd+F/G dispatches to browser when focused
- Visibility filter: skips script/style/hidden/aria-hidden elements
- Stale DOM guard: isConnected check in next/previous scripts
- Navigation cleanup: clears find on didFinish and didFailNavigation
Co-authored-by: Lawrence Chen <54008264+lawrencecchen@users.noreply.github.com>
* Add i18n infrastructure with String Catalog and Japanese translations
Introduce String Catalog (.xcstrings) for localization support:
- Localizable.xcstrings: 195 UI string entries with en and ja translations
- InfoPlist.xcstrings: Info.plist strings (microphone usage, Finder menu items)
- project.pbxproj: add xcstrings to build phase and ja to knownRegions
* Replace hardcoded UI strings with String(localized:defaultValue:)
Migrate all user-facing strings across 11 source files to use
String(localized:defaultValue:) API (macOS 13+). Each string references
a key in Localizable.xcstrings, with the English text preserved as
defaultValue for fallback.
Files modified:
- KeyboardShortcutSettings: 28 shortcut labels
- SocketControlSettings: mode names and descriptions
- TabManager: placement labels, color names, close dialogs
- BrowserPanel/BrowserPanelView: error pages, context menus, tooltips
- UpdateViewModel/UpdatePopoverView/UpdatePill: update UI states
- NotificationsPage: notification panel labels
- SurfaceSearchOverlay: search bar placeholder and tooltips
- AppDelegate: menus, dialogs, command palette items
* Fix localization gaps from review feedback
Address review comments from CodeRabbit, Greptile, and Cubic Dev AI:
- Use interpolated String(localized:) instead of concatenation for
version/progress strings in UpdateViewModel
- Localize remaining hardcoded strings in AppDelegate: window labels,
rename dialog, status menu items, unread notification count
- Localize insecure HTTP alert body in BrowserPanel
- Add 12 new entries to Localizable.xcstrings with Japanese translations
* Fix String(localized:defaultValue:) keys to use StaticString
The localized: parameter requires StaticString when defaultValue: is
used. Move string interpolation from the key to defaultValue only,
and revert maxWidthText to plain strings since they are only used for
layout width calculation.
* Localize remaining UI strings across all source files
Add String(localized:defaultValue:) to all user-facing strings in:
- cmuxApp.swift: settings screen, menus, about panel, dialogs (~180 strings)
- ContentView.swift: command palette, sidebar context menu, dialogs (~200 strings)
- Workspace.swift: rename/move/close tab dialogs, tooltips (~20 strings)
- UpdateTitlebarAccessory.swift: titlebar tooltips, notifications popover (~10 strings)
- TerminalNotificationStore.swift: notification permission dialog (4 strings)
- CmuxWebView.swift: browser context menu items (2 strings)
- AppDelegate.swift: CLI install/uninstall alerts (6 strings)
Add 418 new entries to Localizable.xcstrings with Japanese translations.
Extract sidebar context menu into separate @ViewBuilder to fix Swift
type-checker timeout in large body.
Fix xcstrings format specifiers for interpolated strings (%lld, %@).
Total: 624 localization entries covering the full UI.
* Address review feedback: fix missing localizations and terminology
- Localize javaScriptDialogTitle URL branch in BrowserPanel
- Localize cantReach error message in BrowserPanel
- Localize close other tabs dialog message in TabManager
- Localize workspace accessibility label in ContentView
- Fix unread notification singular/plural (split into two keys)
- Fix insecure connection apostrophe inconsistency (unify to U+2019)
- Rename socketControl.fullOpen.description to socketControl.allowAll.description
- Remove dead code: renameTargetNoun function
- Fix terminology inconsistencies in xcstrings:
- Unify "Developer Tools" to デベロッパツール
- Unify "Jump to Latest Unread" phrasing
- Unify "Flash Focused Panel" terminology
- Fix dialog.enableNotifications.notNow translation
* fix: address remaining PR 819 review feedback
* fix: use a single localized key for close-other-tabs
* fix: avoid inflection markup in close-other-tabs message
* Address review feedback: localize tooltip, fix subtitle concat, unify keys
- Localize menubar tooltip unread count (hardcoded English -> localized)
- Replace subtitle string concatenation anti-pattern with single localized
keys containing interpolation placeholders
- Unify workspace fallback key to workspace.displayName.fallback
- Remove unused workspace.defaultName key from xcstrings
- Add Japanese translations for new tooltip and subtitle keys
* Honor Ghostty background-opacity across all cmux chrome
Parse background-opacity from Ghostty config and propagate it through
the entire chrome pipeline: bonsplit tab bar (via RRGGBBAA hex),
browser panel/omnibar, titlebar, empty panel, and window background.
Decouple glass effect from sidebar blend mode — bgGlassEnabled now
defaults to false so opacity works independently. Add
GhosttyBackgroundTheme helper for consistent color+opacity resolution
across all UI surfaces.
Fixes https://github.com/manaflow-ai/cmux/issues/263
* Titlebar and chrome opacity matches terminal background-opacity
Use CALayer-level opacity for the titlebar background instead of SwiftUI
Color alpha, matching the terminal's Metal compositing path. Account for
the double alpha stacking in the terminal area (Bonsplit container bg +
Ghostty renderer) so the titlebar visually matches.
Also fix opacity-only config changes not triggering titlebar refresh on
Cmd+Shift+, reload.
- Notification/focus flash uses workspace customColor (fallback: accent)
- Selection bar/indicator uses workspace customColor when set
- Flash color propagated through Panel.triggerFlash(color:) API
- Browser panel flash overlay uses workspace color
- Regression tests for flash color resolution
Fixes https://github.com/manaflow-ai/cmux/issues/557
* Hide new-tab browser toggles and align dark-mode button style
* Switch forced dark mode from dimming overlay to dark theme
* Add tri-state browser theme mode for embedded web view
* Hide browser theme menu chevron in toolbar
* Use outline icons for browser theme toggle
* Align browser theme icon tint with DevTools button
* Force monochrome rendering for browser toolbar icons
* Reduce browser theme icon weight for visual parity
* Tune browser theme icon stroke for perceptual color match
* Force flat SF Symbol color rendering for toolbar icons
* Use button popover for browser theme selector
* Address PR 242 follow-ups for titlebar and browser background
* Restore titlebar border per follow-up scope
* Refresh browser under-page color with Ghostty opacity
* Browser: theme blank page fallback for about:blank
* Browser: keep new tabs webview-less until first nav
* Remove border below titlebar
Remove the 1px separator line overlay at the bottom of the custom
titlebar and its associated fakeTitlebarSeparatorColor computed property.
* Remove tab hover background in bonsplit
Update bonsplit submodule to remove the background fill on hovered
non-selected tabs.
* Restore titlebar border with system separator color, hover bg on all tabs, browser theme bg
- Add back 1px bottom border on titlebar using NSColor.separatorColor
(matches bonsplit tab separator color)
- Tab hover background now applies to all tabs including the selected one
- Browser address bar and under-page background now use Ghostty theme
background color instead of window background