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
344 changes: 212 additions & 132 deletions Sources/Cloud/CloudNotificationSync.swift

Large diffs are not rendered by default.

46 changes: 18 additions & 28 deletions Sources/DockSplitStore+TerminalLinkOpening.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,11 @@ extension DockSplitStore: TerminalLinkOpenContainer {
}

func terminalLinkWorkingDirectory(for sourcePanelId: UUID) -> String? {
guard let panelId = panelID(forTerminalLinkSourceID: sourcePanelId) else {
return nil
}
return terminalWorkingDirectory(for: panelId)
terminalWorkingDirectory(for: sourcePanelId)
}

func terminalLinkIsRemoteTerminal(_ sourcePanelId: UUID) -> Bool {
guard let panelId = panelID(forTerminalLinkSourceID: sourcePanelId) else {
return false
}
return detachedSurfaceTransfersByPanelId[panelId]?.isRemoteTerminal == true
}

func cloudTerminalLinkTarget(url: URL, sourcePanelId: UUID) -> CloudTerminalLinkTarget? {
guard let resource = SurfaceCatalog.shared.resource(forPanel: sourcePanelId),
let address = SurfaceCatalog.shared.machineInfo(for: resource.machine)?.privateAddress,
let target = CmuxTuiSurfaceProvider.cloudTerminalLinkTarget(url: url, resource: resource, privateAddress: address) else { return nil }
return target
detachedSurfaceTransfersByPanelId[sourcePanelId]?.isRemoteTerminal == true
}

func deferTerminalFileLinkOpen(
Expand All @@ -39,8 +26,7 @@ extension DockSplitStore: TerminalLinkOpenContainer {
}

func openTerminalBrowserLink(url: URL, sourcePanelId: UUID, focus: Bool = true) -> Bool {
guard let panelId = panelID(forTerminalLinkSourceID: sourcePanelId),
let sourcePane = paneId(forPanelId: panelId) else { return false }
guard let sourcePane = paneId(forPanelId: sourcePanelId) else { return false }
if let targetPane = BrowserRightSidePaneResolver().preferredPane(
from: sourcePane,
in: bonsplitController
Expand All @@ -50,27 +36,31 @@ extension DockSplitStore: TerminalLinkOpenContainer {
kind: .browser,
inPane: targetPane,
url: url,
focus: false
focus: focus
) else { return false }
if focus { focusPanelFromDockInteraction(
panelId,
window: NSApp.keyWindow ?? NSApp.mainWindow
) }
if focus {
focusPanelFromDockInteraction(
panelId,
window: NSApp.keyWindow ?? NSApp.mainWindow
)
}
return true
}
if focus { noteKeyboardFocusIntent(window: NSApp.keyWindow ?? NSApp.mainWindow) }
guard let panelId = newSplit(
kind: .browser,
orientation: .horizontal,
insertFirst: false,
sourcePanelId: panelId,
sourcePanelId: sourcePanelId,
url: url,
focus: false
focus: focus
) else { return false }
if focus { focusPanelFromDockInteraction(
panelId,
window: NSApp.keyWindow ?? NSApp.mainWindow
) }
if focus {
focusPanelFromDockInteraction(
panelId,
window: NSApp.keyWindow ?? NSApp.mainWindow
)
}
return true
}
}
39 changes: 39 additions & 0 deletions Sources/Surfaces/CloudBrowserOpenRequest.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import Foundation

extension CmuxTuiSurfaceProvider {
/// Private notification title used to request a Mac browser pane from a VM.
static let cloudBrowserOpenNotificationTitle = "cmux.open-url"
}

extension CmuxTuiSurfaceProvider {
/// Consumes a guest URL request and opens it beside the source terminal.
@MainActor
func handleCloudBrowserOpenRequest(
_ row: CloudVMNotificationRow,
target: CloudNotificationDeliveryTarget
) -> Bool {
guard row.title == Self.cloudBrowserOpenNotificationTitle else { return false }
guard let terminalID = row.terminalID,
let url = URL(string: row.body),
["http", "https"].contains(url.scheme?.lowercased() ?? ""),
let sourcePanelID = target.panelID else {
return false
}
let terminalResourceID = SurfaceResourceID(machine: machine, kind: .terminal, key: terminalID)
guard catalog.resources[terminalResourceID] != nil else {
return false
}

// Match terminal-link policy: the setting chooses an embedded cmux
// browser, while a disabled browser opens the user's system browser.
return TerminalLinkOpenCoordinator(
deferOperation: { operation in operation() }
).open(TerminalLinkOpenRequest(
rawValue: url.absoluteString,
sourceWorkspaceId: target.workspaceID,
sourcePanelId: sourcePanelID,
workingDirectory: nil,
focus: false
))
}
}
Loading
Loading