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
17 changes: 8 additions & 9 deletions Sources/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9416,16 +9416,14 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
writeGotoSplitTestData(updates)
}

private func recordGotoSplitZoomIfNeeded() {
private func recordGotoSplitZoomIfNeeded(tabManager: TabManager? = nil) {
guard isGotoSplitUITestRecordingEnabled() else { return }
guard let workspace = tabManager?.selectedWorkspace else { return }
guard let workspace = (tabManager ?? self.tabManager)?.selectedWorkspace else { return }

func snapshot(for workspace: Workspace) -> ([String: String], Bool) {
let browserPanel = workspace.panels.values.compactMap { $0 as? BrowserPanel }.first
let otherTerminal = workspace.panels.values.compactMap { $0 as? TerminalPanel }.first
let browserSnapshot = browserPanel.flatMap {
BrowserWindowPortalRegistry.debugSnapshot(for: $0.webView)
}
let browserSnapshot = browserPanel.flatMap { BrowserWindowPortalRegistry.debugSnapshot(for: $0.webView) }

var updates = self.gotoSplitFindStateSnapshot(for: workspace)
updates["splitZoomedAfterToggle"] = workspace.bonsplitController.isSplitZoomed ? "true" : "false"
Expand Down Expand Up @@ -9497,7 +9495,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent

@MainActor
func evaluate() {
guard !resolved, let currentWorkspace = self.tabManager?.selectedWorkspace else { return }
guard !resolved, let currentWorkspace = (tabManager ?? self.tabManager)?.selectedWorkspace else { return }
let (updates, settled) = snapshot(for: currentWorkspace)
guard settled else { return }
finish(with: updates)
Expand Down Expand Up @@ -9532,7 +9530,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { [weak self] in
guard let self else { return }
Task { @MainActor in
guard !resolved, let currentWorkspace = self.tabManager?.selectedWorkspace else { return }
guard !resolved, let currentWorkspace = (tabManager ?? self.tabManager)?.selectedWorkspace else { return }
finish(with: snapshot(for: currentWorkspace).0)
}
}
Expand Down Expand Up @@ -11243,9 +11241,10 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
}

if matchConfiguredShortcut(event: event, action: .toggleSplitZoom) {
_ = tabManager?.toggleFocusedSplitZoom()
let routedManager = preferredMainWindowContextForShortcutRouting(event: event)?.tabManager ?? tabManager
_ = routedManager?.toggleFocusedSplitZoom()
Comment thread
austinywang marked this conversation as resolved.
Comment thread
austinywang marked this conversation as resolved.
#if DEBUG
recordGotoSplitZoomIfNeeded()
recordGotoSplitZoomIfNeeded(tabManager: routedManager)
#endif
return true
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/KeyboardShortcutSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1914,7 +1914,7 @@ struct StoredShortcut: Codable, Equatable, Hashable {
}

var isUnbound: Bool {
key.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
key.isEmpty
}

var firstStroke: ShortcutStroke {
Expand Down
47 changes: 14 additions & 33 deletions Sources/Panels/CmuxWebView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -591,22 +591,22 @@ final class CmuxWebView: WKWebView {
extra: "handled=\(handled ? 1 : 0)"
)
}
func finish(_ result: Bool) -> Bool {
handled = result
return result
}
#else
func finish(_ result: Bool) -> Bool { result }
#endif
if event.keyCode == 36 || event.keyCode == 76 {
// Always bypass app/menu key-equivalent routing for Return/Enter so WebKit
// receives the keyDown path used by form submission handlers.
Comment thread
cursor[bot] marked this conversation as resolved.
return false
return finish(AppDelegate.shared?.handleBrowserSurfaceKeyEquivalent(event) == true)
}

let flags = event.modifierFlags.intersection(.deviceIndependentFlagsMask)
// Menu/app shortcut routing is only needed for Command equivalents
// (New Tab, Close Tab, tab switching, split commands, etc).
guard flags.contains(.command) else {
let result = super.performKeyEquivalent(with: event)
#if DEBUG
handled = result
#endif
return result
return finish(super.performKeyEquivalent(with: event))
}

if Self.isPasteAsPlainTextCommandEquivalent(event) {
Expand All @@ -619,10 +619,7 @@ final class CmuxWebView: WKWebView {
if result {
lastPasteAsPlainTextPerformKeyEventTimestamp = nil
}
#if DEBUG
handled = result
#endif
return result
return finish(result)
}

var replayedBrowserFindShortcutIntoWebContent = false
Expand All @@ -633,34 +630,21 @@ final class CmuxWebView: WKWebView {
) {
replayedBrowserFindShortcutIntoWebContent = true
let result = super.performKeyEquivalent(with: event)
#if DEBUG
handled = result
#endif
if result {
return true
return finish(true)
}
}

if !shouldRouteCommandEquivalentDirectlyToMainMenu(event) {
let result = super.performKeyEquivalent(with: event)
#if DEBUG
handled = result
#endif
return result
return finish(super.performKeyEquivalent(with: event))
}

if AppDelegate.shared?.handleBrowserSurfaceKeyEquivalentBeforeMainMenu(event) == true {
#if DEBUG
handled = true
#endif
return true
return finish(true)
}

if let menu = NSApp.mainMenu, menu.performKeyEquivalent(with: event) {
#if DEBUG
handled = true
#endif
return true
return finish(true)
}

let result: Bool
Expand All @@ -671,10 +655,7 @@ final class CmuxWebView: WKWebView {
} else {
result = super.performKeyEquivalent(with: event)
}
#if DEBUG
handled = result
#endif
return result
return finish(result)
}

override func keyDown(with event: NSEvent) {
Expand Down
69 changes: 69 additions & 0 deletions cmuxTests/AppDelegateEqualizeSplitsShortcutTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,57 @@ import XCTest

@MainActor
final class AppDelegateEqualizeSplitsShortcutTests: XCTestCase {
func testCmdShiftReturnFocusedBrowserTogglesSplitZoom() {
withTemporaryShortcut(action: .toggleSplitZoom) {
guard let appDelegate = AppDelegate.shared else {
XCTFail("Expected AppDelegate.shared")
return
}

let windowId = appDelegate.createMainWindow()
defer { closeWindow(withId: windowId) }

guard let window = window(withId: windowId),
let manager = appDelegate.tabManagerFor(windowId: windowId),
let workspace = manager.selectedWorkspace,
let browserPanelId = manager.openBrowser(inWorkspace: workspace.id, preferSplitRight: true),
let browserPanel = workspace.browserPanel(for: browserPanelId),
let event = makeKeyDownEvent(key: "\r", modifiers: [.command, .shift], keyCode: 36, windowNumber: window.windowNumber) else {
XCTFail("Expected focused browser panel and Cmd+Shift+Return event")
return
}

workspace.focusPanel(browserPanel.id)
XCTAssertEqual(workspace.focusedPanelId, browserPanel.id)
XCTAssertFalse(workspace.bonsplitController.isSplitZoomed)

var didAttachForTest = false
if browserPanel.webView.superview == nil {
browserPanel.webView.frame = window.contentView?.bounds ?? .zero
window.contentView?.addSubview(browserPanel.webView)
didAttachForTest = true
}
defer {
if didAttachForTest { browserPanel.webView.removeFromSuperview() }
}

window.makeKeyAndOrderFront(nil)
XCTAssertTrue(window.makeFirstResponder(browserPanel.webView))
XCTAssertTrue(KeyboardShortcutSettings.shortcut(for: .toggleSplitZoom).matches(event: event))

#if DEBUG
XCTAssertTrue(appDelegate.debugHandleShortcutMonitorEvent(event: event))
XCTAssertTrue(workspace.bonsplitController.isSplitZoomed)
XCTAssertTrue(workspace.clearSplitZoom())
#else
XCTFail("debugHandleShortcutMonitorEvent is only available in DEBUG")
#endif

XCTAssertTrue(browserPanel.webView.performKeyEquivalent(with: event))
XCTAssertTrue(workspace.bonsplitController.isSplitZoomed)
}
}

func testConfiguredEqualizeSplitsShortcutBalancesWorkspaceDividers() {
guard let appDelegate = AppDelegate.shared else {
XCTFail("Expected AppDelegate.shared")
Expand Down Expand Up @@ -149,6 +200,24 @@ final class AppDelegateEqualizeSplitsShortcutTests: XCTestCase {
)
}

private func withTemporaryShortcut(
action: KeyboardShortcutSettings.Action,
shortcut: StoredShortcut? = nil,
_ body: () -> Void
) {
let hadPersistedShortcut = UserDefaults.standard.object(forKey: action.defaultsKey) != nil
let originalShortcut = KeyboardShortcutSettings.shortcut(for: action)
defer {
if hadPersistedShortcut {
KeyboardShortcutSettings.setShortcut(originalShortcut, for: action)
} else {
KeyboardShortcutSettings.resetShortcut(for: action)
}
}
KeyboardShortcutSettings.setShortcut(shortcut ?? action.defaultShortcut, for: action)
body()
}

private func window(withId windowId: UUID) -> NSWindow? {
let identifier = "cmux.main.\(windowId.uuidString)"
return NSApp.windows.first(where: { $0.identifier?.rawValue == identifier })
Expand Down