Skip to content
Closed
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
85 changes: 85 additions & 0 deletions Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -10037,6 +10037,74 @@
}
}
},
"command.rightSidebarShow.title": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Show Right Sidebar"
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "右サイドバーを表示"
}
}
}
},
"command.rightSidebarHide.title": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Hide Right Sidebar"
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "右サイドバーを非表示"
}
}
}
},
"command.rightSidebarFocus.title": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Focus Right Sidebar"
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "右サイドバーにフォーカス"
}
}
}
},
"command.rightSidebarSessions.title": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Show Sidebar Sessions"
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "サイドバーのセッションを表示"
}
}
}
},
"command.openRightSidebarToolAsPane.subtitle": {
"extractionState": "manual",
"localizations": {
Expand Down Expand Up @@ -108280,6 +108348,23 @@
}
}
},
"shortcut.switchRightSidebarToVault.label": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Show Sidebar Vault"
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "サイドバーのボールトを表示"
}
}
}
},
"shortcut.switchRightSidebarToSessions.label": {
"extractionState": "manual",
"localizations": {
Expand Down
217 changes: 160 additions & 57 deletions Sources/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5873,9 +5873,10 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent

func applyRightSidebarRemoteCommand(
_ command: RightSidebarRemoteCommand,
target: RightSidebarRemoteTarget = RightSidebarRemoteTarget()
target: RightSidebarRemoteTarget = RightSidebarRemoteTarget(),
preferredWindow: NSWindow? = nil
) -> RightSidebarRemoteApplyResult {
let context = rightSidebarRemoteContext(target: target)
let context = rightSidebarRemoteContext(target: target, preferredWindow: preferredWindow)
if !target.isActiveTarget, context == nil {
return .failure(String(localized: "rightSidebar.remote.error.targetNotFound", defaultValue: "ERROR: Right sidebar target not found"))
}
Expand Down Expand Up @@ -5961,7 +5962,156 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
}
}

private func rightSidebarRemoteContext(target: RightSidebarRemoteTarget) -> MainWindowContext? {
@discardableResult
func executeBuiltInRightSidebarAction(
_ action: CmuxSurfaceTabBarBuiltInAction,
preferredWindow: NSWindow? = nil,
onExecuted: (() -> Void)? = nil
) -> Bool {
executeBuiltInAction(
action,
scope: .rightSidebarOnly,
preferredWindow: preferredWindow,
onExecuted: onExecuted
)
}

@discardableResult
func executeSurfaceTabBarBuiltInAction(
_ action: CmuxSurfaceTabBarBuiltInAction,
tabManager: TabManager?,
preferredWindow: NSWindow? = nil
) -> Bool {
executeBuiltInAction(
action,
scope: .surfaceTabBar(tabManager),
preferredWindow: preferredWindow
)
}

private enum BuiltInActionExecutionScope {
case configured(MainWindowContext)
case surfaceTabBar(TabManager?)
case rightSidebarOnly
}

@discardableResult
private func executeBuiltInAction(
_ action: CmuxSurfaceTabBarBuiltInAction,
scope: BuiltInActionExecutionScope,
preferredWindow: NSWindow? = nil,
onExecuted: (() -> Void)? = nil
) -> Bool {
switch action {
case .rightSidebarToggle, .rightSidebarShow, .rightSidebarHide, .rightSidebarFocus,
.rightSidebarFiles, .rightSidebarFind, .rightSidebarVault, .rightSidebarSessions,
.rightSidebarFeed, .rightSidebarDock:
guard let command = action.rightSidebarRemoteCommand else {
return false
}
switch applyRightSidebarRemoteCommand(command, preferredWindow: preferredWindow) {
case .ok:
onExecuted?()
return true
case .state, .failure:
return false
}

case .newWorkspace:
switch scope {
case .configured(let context):
context.tabManager.addWorkspace()
onExecuted?()
return true
case .surfaceTabBar(let tabManager):
guard let tabManager else { return false }
tabManager.addWorkspace()
return true
case .rightSidebarOnly:
return false
}

case .cloudVM:
switch scope {
case .configured(let context):
let didStart = performCloudVMAction(
tabManager: context.tabManager,
preferredWindow: resolvedWindow(for: context) ?? preferredWindow,
debugSource: "configured.cmux.cloudvm"
)
if didStart { onExecuted?() }
return didStart
case .surfaceTabBar(let tabManager):
return performCloudVMAction(
tabManager: tabManager,
preferredWindow: preferredWindow,
debugSource: "surfaceTabBar.cloudVM"
)
case .rightSidebarOnly:
return false
}

case .newTerminal:
guard case .configured(let context) = scope else {
return false
}
context.tabManager.newSurface()
onExecuted?()
return true

case .newBrowser:
guard case .configured(let context) = scope else {
return false
}
let previousTabManager = tabManager
tabManager = context.tabManager
defer { tabManager = previousTabManager }
guard openBrowserAndFocusAddressBar(insertAtEnd: true) != nil else {
return false
}
onExecuted?()
return true

case .splitRight:
guard case .configured(let context) = scope else {
return false
}
if shouldSuppressSplitShortcutForTransientTerminalFocusState(
direction: .right,
tabManager: context.tabManager
) {
return true
}
let didSplit = performSplitShortcut(
direction: .right,
preferredWindow: preferredWindow ?? NSApp.keyWindow ?? NSApp.mainWindow
)
if didSplit { onExecuted?() }
return didSplit

case .splitDown:
guard case .configured(let context) = scope else {
return false
}
if shouldSuppressSplitShortcutForTransientTerminalFocusState(
direction: .down,
tabManager: context.tabManager
) {
return true
}
let didSplit = performSplitShortcut(
direction: .down,
preferredWindow: preferredWindow ?? NSApp.keyWindow ?? NSApp.mainWindow
)
if didSplit { onExecuted?() }
return didSplit
}
}

private func rightSidebarRemoteContext(
target: RightSidebarRemoteTarget,
preferredWindow: NSWindow? = nil
) -> MainWindowContext? {
if let windowId = target.windowId {
return mainWindowContexts.values.first(where: { $0.windowId == windowId })
}
Expand All @@ -5970,7 +6120,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
context.tabManager.tabs.contains(where: { $0.id == workspaceId })
}
}
return preferredRegisteredMainWindowContext()
return preferredRegisteredMainWindowContext(preferredWindow: preferredWindow)
}

@discardableResult
Expand Down Expand Up @@ -13641,59 +13791,12 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
) -> Bool {
switch action.action {
case .builtIn(let builtIn):
switch builtIn {
case .newWorkspace:
context.tabManager.addWorkspace()
onExecuted?()
return true
case .cloudVM:
let didStart = performCloudVMAction(
tabManager: context.tabManager,
preferredWindow: resolvedWindow(for: context) ?? preferredWindow,
debugSource: "configured.cmux.cloudvm"
)
if didStart { onExecuted?() }
return didStart
case .newTerminal:
context.tabManager.newSurface()
onExecuted?()
return true
case .newBrowser:
let previousTabManager = tabManager
tabManager = context.tabManager
defer { tabManager = previousTabManager }
guard openBrowserAndFocusAddressBar(insertAtEnd: true) != nil else {
return false
}
onExecuted?()
return true
case .splitRight:
if shouldSuppressSplitShortcutForTransientTerminalFocusState(
direction: .right,
tabManager: context.tabManager
) {
return true
}
let didSplit = performSplitShortcut(
direction: .right,
preferredWindow: preferredWindow ?? NSApp.keyWindow ?? NSApp.mainWindow
)
if didSplit { onExecuted?() }
return didSplit
case .splitDown:
if shouldSuppressSplitShortcutForTransientTerminalFocusState(
direction: .down,
tabManager: context.tabManager
) {
return true
}
let didSplit = performSplitShortcut(
direction: .down,
preferredWindow: preferredWindow ?? NSApp.keyWindow ?? NSApp.mainWindow
)
if didSplit { onExecuted?() }
return didSplit
}
return executeBuiltInAction(
builtIn,
scope: .configured(context),
preferredWindow: preferredWindow,
onExecuted: onExecuted
)
case .command, .agent, .workspaceCommand:
guard let cmuxConfigStore = context.cmuxConfigStore else {
return false
Expand Down
27 changes: 2 additions & 25 deletions Sources/CmuxConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1499,34 +1499,11 @@ struct CmuxResolvedConfigAction: Identifiable, Sendable, Hashable {
}

static func builtIn(_ builtIn: CmuxSurfaceTabBarBuiltInAction) -> CmuxResolvedConfigAction {
let title: String
let keywords: [String]
switch builtIn {
case .newWorkspace:
title = String(localized: "command.newWorkspace.title", defaultValue: "New Workspace")
keywords = ["create", "new", "workspace"]
case .cloudVM:
title = String(localized: "command.cloudVM.title", defaultValue: "Start Cloud VM")
keywords = ["cloud", "vm", "virtual", "machine", "remote"]
case .newTerminal:
title = String(localized: "command.newTerminalTab.title", defaultValue: "New Terminal Tab")
keywords = ["new", "terminal", "tab", "surface"]
case .newBrowser:
title = String(localized: "command.newBrowserTab.title", defaultValue: "New Browser Tab")
keywords = ["new", "browser", "tab", "surface"]
case .splitRight:
title = String(localized: "command.terminalSplitRight.title", defaultValue: "Split Right")
keywords = ["terminal", "split", "right"]
case .splitDown:
title = String(localized: "command.terminalSplitDown.title", defaultValue: "Split Down")
keywords = ["terminal", "split", "down"]
}

return CmuxResolvedConfigAction(
id: builtIn.configID,
title: title,
title: builtIn.defaultTitle,
subtitle: String(localized: "command.cmuxConfig.builtInSubtitle", defaultValue: "cmux"),
keywords: keywords,
keywords: builtIn.defaultKeywords,
palette: true,
shortcut: nil,
icon: .symbol(builtIn.defaultIcon),
Expand Down
Loading
Loading