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
27 changes: 22 additions & 5 deletions Sources/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2647,6 +2647,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
.trimmingCharacters(in: .whitespacesAndNewlines)
let lineFormat = env["CMUX_UI_TEST_TERMINAL_CMD_CLICK_LINE_FORMAT"]?
.trimmingCharacters(in: .whitespacesAndNewlines)
let mouseReportingEnabled = env["CMUX_UI_TEST_TERMINAL_CMD_CLICK_MOUSE_REPORTING"] == "1"
let linePrefix = env["CMUX_UI_TEST_TERMINAL_CMD_CLICK_LINE_PREFIX"] ?? ""
let displaySuffix = env["CMUX_UI_TEST_TERMINAL_CMD_CLICK_DISPLAY_SUFFIX"] ?? ""
let displayAsAbsolutePath = env["CMUX_UI_TEST_TERMINAL_CMD_CLICK_DISPLAY_AS_ABSOLUTE_PATH"] == "1"
Expand Down Expand Up @@ -2688,48 +2689,59 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
resolvedLineFormat = "alt_screen_log"
case "osc8":
resolvedLineFormat = "osc8"
case "url":
resolvedLineFormat = "url"
default:
resolvedLineFormat = "grid"
}
cmuxDebugLog(
"cmdclick.ui.setup start manifest=\(manifestPath) fixture=\(fixtureDirectory) " +
"command=\(commandPath ?? "nil") display=\(resolvedDisplayMode) " +
"lineFormat=\(resolvedLineFormat) " +
"mouseReporting=\(mouseReportingEnabled ? 1 : 0) " +
"file=\(resolvedFileName)"
)
func singleQuotedShellLiteral(_ text: String) -> String {
text.replacingOccurrences(of: "'", with: "'\"'\"'")
}
let displayToken: String
let shellCommand: String
// DECSET 1000 is the terminal protocol state tmux enables for
// `set -g mouse on`. Driving that state directly keeps this test
// hermetic while exercising the same Ghostty mouse-reporting gate.
let mouseReportingCommand = mouseReportingEnabled ? "printf '\\033[?1000h'; " : ""
switch resolvedLineFormat {
case "osc8":
displayToken = resolvedFileName
let escapedDisplayToken = singleQuotedShellLiteral(displayToken)
let escapedURL = singleQuotedShellLiteral(expectedFileURL.absoluteString)
shellCommand = "clear\rfor i in $(seq 1 48); do printf '\\033]8;;%s\\033\\\\%s\\033]8;;\\033\\\\\\n' '\(escapedURL)' '\(escapedDisplayToken)'; done\r"
shellCommand = "clear\r\(mouseReportingCommand)for i in $(seq 1 48); do printf '\\033]8;;%s\\033\\\\%s\\033]8;;\\033\\\\\\n' '\(escapedURL)' '\(escapedDisplayToken)'; done\r"
case "url":
displayToken = "https://github.com"
let shellBlockLine = singleQuotedShellLiteral(displayToken)
shellCommand = "clear\r\(mouseReportingCommand)for i in $(seq 1 48); do printf '%s\\n' '\(shellBlockLine)'; done\r"
case "log":
displayToken = "\(baseDisplayToken)\(displaySuffix)"
let blockLine = "\(linePrefix)\(displayToken)"
let shellBlockLine = singleQuotedShellLiteral(blockLine)
shellCommand = "clear\rfor i in $(seq 1 48); do printf '%s\\n' '\(shellBlockLine)'; done\r"
shellCommand = "clear\r\(mouseReportingCommand)for i in $(seq 1 48); do printf '%s\\n' '\(shellBlockLine)'; done\r"
case "alt_screen_log":
displayToken = "\(baseDisplayToken)\(displaySuffix)"
let blockLine = "\(linePrefix)\(displayToken)"
let shellBlockLine = singleQuotedShellLiteral(blockLine)
shellCommand = "clear\rprintf '\\033[?1049h\\033[H\\033[2J'; for i in $(seq 1 48); do printf '%s\\n' '\(shellBlockLine)'; done\r"
shellCommand = "clear\rprintf '\\033[?1049h\\033[H\\033[2J'; \(mouseReportingCommand)for i in $(seq 1 48); do printf '%s\\n' '\(shellBlockLine)'; done\r"
default:
switch resolvedDisplayMode {
case "raw":
displayToken = "\(baseDisplayToken)\(displaySuffix)"
let blockLine = "\(displayToken) OtherFile"
let shellBlockLine = singleQuotedShellLiteral(blockLine)
shellCommand = "clear\rfor i in $(seq 1 48); do printf '%s\\n' '\(shellBlockLine)'; done\r"
shellCommand = "clear\r\(mouseReportingCommand)for i in $(seq 1 48); do printf '%s\\n' '\(shellBlockLine)'; done\r"
default:
displayToken = "\(escapedToken)\(displaySuffix)"
let blockLine = Array(repeating: displayToken, count: 3).joined(separator: " ")
let shellBlockLine = singleQuotedShellLiteral(blockLine)
shellCommand = "clear\rfor i in $(seq 1 48); do printf '%s\\n' '\(shellBlockLine)'; done\r"
shellCommand = "clear\r\(mouseReportingCommand)for i in $(seq 1 48); do printf '%s\\n' '\(shellBlockLine)'; done\r"
}
}
let deadline = Date().addingTimeInterval((commandPath?.isEmpty == false) ? 60.0 : 20.0)
Expand Down Expand Up @@ -2949,6 +2961,11 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
payload["surfaceId"] = terminalPanel.id.uuidString
payload["terminalVisibleInUI"] = terminalPanel.hostedView.debugPortalVisibleInUI ? "1" : "0"
payload["terminalFrameInWindow"] = rectPayload(terminalFrame)
if mouseReportingEnabled {
payload["mouseReportingCaptured"] = terminalPanel.surface.surface.map {
ghostty_surface_mouse_captured($0) ? "1" : "0"
} ?? "0"
}
}
if let window {
payload["windowFrame"] = rectPayload(window.frame)
Expand Down
40 changes: 38 additions & 2 deletions cmuxUITests/TerminalCmdClickUITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ final class TerminalCmdClickUITests: XCTestCase {
case log
case altScreenLog = "alt_screen_log"
case osc8
case plainURL = "url"
}

private struct SetupData {
Expand Down Expand Up @@ -227,6 +228,37 @@ final class TerminalCmdClickUITests: XCTestCase {
)
}

func testStationaryCmdClickPlainURLWithMouseReportingOpensURL() throws {
let app = launchApp(
displayMode: .raw,
lineFormat: .plainURL,
captureOpenPaths: false,
captureHoverDiagnostics: false,
mouseReporting: true
)
defer { app.terminate() }

let setup = try waitForReadySetup()
XCTAssertEqual(
setup.payload["mouseReportingCaptured"] as? String,
"1",
"Expected the fixture to enable terminal mouse reporting before the click. payload=\(setup.payload)"
)
let expectedURL = "https://github.com"
let result = try runCommand(action: "stationary_cmd_click_token")
XCTAssertEqual(
result["lastCommandSucceeded"] as? String,
"1",
"Expected Cmd-click to open a plain URL while mouse reporting is active. result=\(result)"
)

let openedURLs = waitForCapturedOpenPaths(timeout: 5.0, path: openURLCapturePath)
XCTAssertTrue(
openedURLs.contains(expectedURL),
"Expected Cmd-click to emit the plain URL while mouse reporting is active. opened=\(openedURLs)"
)
}

func testCmdClickOsc8FileHyperlinkOpensExactlyOneHandler() throws {
let fileName = "Cmd Click Fixture.txt"
let app = launchApp(
Expand Down Expand Up @@ -853,7 +885,8 @@ final class TerminalCmdClickUITests: XCTestCase {
openSupportedFilesInCmux: Bool = false,
openMarkdownInCmuxViewer: Bool? = nil,
quicklookOverride: String? = nil,
viewportOffsetDelta: Int? = nil
viewportOffsetDelta: Int? = nil,
mouseReporting: Bool = false
) -> XCUIApplication {
let app = XCUIApplication.cmuxTestApplication()
app.launchEnvironment["CMUX_TAG"] = "ui-test-terminal-cmd-click"
Expand All @@ -865,6 +898,9 @@ final class TerminalCmdClickUITests: XCTestCase {
app.launchEnvironment["CMUX_UI_TEST_TERMINAL_CMD_CLICK_FILE_NAME"] = fileName
app.launchEnvironment["CMUX_UI_TEST_TERMINAL_CMD_CLICK_DISPLAY_MODE"] = displayMode.rawValue
app.launchEnvironment["CMUX_UI_TEST_TERMINAL_CMD_CLICK_LINE_FORMAT"] = lineFormat.rawValue
if mouseReporting {
app.launchEnvironment["CMUX_UI_TEST_TERMINAL_CMD_CLICK_MOUSE_REPORTING"] = "1"
}
app.launchEnvironment["CMUX_UI_TEST_OPEN_SUPPORTED_FILES_IN_CMUX"] = openSupportedFilesInCmux ? "1" : "0"
if !displaySuffix.isEmpty {
app.launchEnvironment["CMUX_UI_TEST_TERMINAL_CMD_CLICK_DISPLAY_SUFFIX"] = displaySuffix
Expand All @@ -886,7 +922,7 @@ final class TerminalCmdClickUITests: XCTestCase {
if captureOpenPaths {
app.launchEnvironment["CMUX_UI_TEST_CAPTURE_OPEN_PATH"] = openCapturePath
}
if lineFormat == .osc8 {
if lineFormat == .osc8 || lineFormat == .plainURL {
app.launchEnvironment["CMUX_UI_TEST_CAPTURE_OPEN_URL_PATH"] = openURLCapturePath
}
if captureHoverDiagnostics {
Expand Down
3 changes: 2 additions & 1 deletion docs/ghostty-fork.md
Original file line number Diff line number Diff line change
Expand Up @@ -1697,7 +1697,8 @@ tend to conflict together during rebases.
`mouseLinkRefreshAllowedState`) that also allows local link handling when the
ctrl/super modifier is held, using the effective mouse-reporting state
(`isMouseReporting()`), matching iTerm2 and macOS Terminal. Fixes
https://github.com/manaflow-ai/cmux/issues/5128.
https://github.com/manaflow-ai/cmux/issues/5128 and the original tmux
reproduction in https://github.com/manaflow-ai/cmux/issues/2896.
- Follow-up (#74): `mouseButtonCallback` ran the link-open path only on
release, while the mouse-report path ran for both press and release and only
broke out for the shift-release case — so a Cmd-click over a link still
Expand Down
Loading