Use pane TTY fallback for tmux Shift+Enter
This commit is contained in:
parent
f4c99d34f3
commit
8336aae865
3 changed files with 97 additions and 26 deletions
|
|
@ -1930,12 +1930,10 @@ class GhosttyApp {
|
|||
modifierFlags: NSEvent.ModifierFlags,
|
||||
isInsideTmux: Bool,
|
||||
userConfigDefinesShiftEnterBinding: Bool,
|
||||
ghosttyHasBinding: Bool,
|
||||
hasMarkedText: Bool
|
||||
) -> Bool {
|
||||
guard isInsideTmux else { return false }
|
||||
guard !userConfigDefinesShiftEnterBinding else { return false }
|
||||
guard !ghosttyHasBinding else { return false }
|
||||
guard !hasMarkedText else { return false }
|
||||
|
||||
let normalizedModifiers = terminalKeyboardCopyModeNormalizedModifiers(modifierFlags)
|
||||
|
|
@ -6236,27 +6234,44 @@ class GhosttyNSView: NSView, NSUserInterfaceValidations {
|
|||
event: NSEvent,
|
||||
surface: ghostty_surface_t
|
||||
) -> Bool {
|
||||
guard !GhosttyApp.shared.userConfigDefinesShiftEnterBinding else { return false }
|
||||
let userConfigDefinesShiftEnterBinding = GhosttyApp.shared.userConfigDefinesShiftEnterBinding
|
||||
guard !userConfigDefinesShiftEnterBinding else { return false }
|
||||
let normalizedModifiers = terminalKeyboardCopyModeNormalizedModifiers(event.modifierFlags)
|
||||
guard normalizedModifiers == [.shift] else { return false }
|
||||
guard event.keyCode == 36 || event.keyCode == 76 else { return false }
|
||||
guard let terminalSurface else { return false }
|
||||
let tabId = terminalSurface.tabId
|
||||
let panelId = terminalSurface.id
|
||||
let isInsideTmux = AppDelegate.shared?
|
||||
guard let tab = AppDelegate.shared?
|
||||
.tabManagerFor(tabId: tabId)?
|
||||
.tabs
|
||||
.first(where: { $0.id == tabId })?
|
||||
.panelIsInsideTmux(panelId: panelId) ?? false
|
||||
let ghosttyHasBinding = ghosttyBindingFlags(for: event, surface: surface) != nil
|
||||
return GhosttyApp.shouldRemapShiftEnterForTmux(
|
||||
.first(where: { $0.id == tabId }) else {
|
||||
return false
|
||||
}
|
||||
let reportedInsideTmux = tab.panelIsInsideTmux(panelId: panelId)
|
||||
// Shell-side tmux telemetry can lag behind pane focus changes, so fall back to
|
||||
// the current foreground process on the pane TTY before deciding whether to remap.
|
||||
let detectedInsideTmux = tab.surfaceTTYNames[panelId].map {
|
||||
TerminalSSHSessionDetector.isInsideTmux(forTTY: $0)
|
||||
} ?? false
|
||||
let isInsideTmux = reportedInsideTmux || detectedInsideTmux
|
||||
if detectedInsideTmux != reportedInsideTmux {
|
||||
AppDelegate.shared?
|
||||
.tabManagerFor(tabId: tabId)?
|
||||
.updateSurfaceTmuxState(
|
||||
tabId: tabId,
|
||||
surfaceId: panelId,
|
||||
isInsideTmux: detectedInsideTmux
|
||||
)
|
||||
}
|
||||
let shouldRemap = GhosttyApp.shouldRemapShiftEnterForTmux(
|
||||
keyCode: event.keyCode,
|
||||
modifierFlags: event.modifierFlags,
|
||||
isInsideTmux: isInsideTmux,
|
||||
userConfigDefinesShiftEnterBinding: false,
|
||||
ghosttyHasBinding: ghosttyHasBinding,
|
||||
userConfigDefinesShiftEnterBinding: userConfigDefinesShiftEnterBinding,
|
||||
hasMarkedText: hasMarkedText()
|
||||
)
|
||||
return shouldRemap
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
|
|
|
|||
|
|
@ -420,6 +420,24 @@ enum TerminalSSHSessionDetector {
|
|||
)
|
||||
}
|
||||
|
||||
static func isInsideTmux(forTTY ttyName: String) -> Bool {
|
||||
let normalizedTTY = normalizeTTYName(ttyName)
|
||||
guard !normalizedTTY.isEmpty else { return false }
|
||||
return isInsideTmuxForTesting(
|
||||
ttyName: normalizedTTY,
|
||||
processes: processSnapshots(forTTY: normalizedTTY)
|
||||
)
|
||||
}
|
||||
|
||||
static func isInsideTmuxForTesting(
|
||||
ttyName: String,
|
||||
processes: [ProcessSnapshot]
|
||||
) -> Bool {
|
||||
let normalizedTTY = normalizeTTYName(ttyName)
|
||||
guard !normalizedTTY.isEmpty else { return false }
|
||||
return processes.contains { isForegroundProcess($0, ttyName: normalizedTTY, executableName: "tmux") }
|
||||
}
|
||||
|
||||
static func detectForTesting(
|
||||
ttyName: String,
|
||||
processes: [ProcessSnapshot],
|
||||
|
|
@ -474,8 +492,16 @@ enum TerminalSSHSessionDetector {
|
|||
}
|
||||
|
||||
private static func isForegroundSSHProcess(_ process: ProcessSnapshot, ttyName: String) -> Bool {
|
||||
isForegroundProcess(process, ttyName: ttyName, executableName: "ssh")
|
||||
}
|
||||
|
||||
private static func isForegroundProcess(
|
||||
_ process: ProcessSnapshot,
|
||||
ttyName: String,
|
||||
executableName: String
|
||||
) -> Bool {
|
||||
normalizeTTYName(process.tty) == normalizeTTYName(ttyName) &&
|
||||
process.executableName == "ssh" &&
|
||||
process.executableName == executableName &&
|
||||
process.pgid > 0 &&
|
||||
process.tpgid > 0 &&
|
||||
process.pgid == process.tpgid
|
||||
|
|
|
|||
|
|
@ -2559,7 +2559,6 @@ final class GhosttyMouseFocusTests: XCTestCase {
|
|||
modifierFlags: [.shift],
|
||||
isInsideTmux: true,
|
||||
userConfigDefinesShiftEnterBinding: false,
|
||||
ghosttyHasBinding: false,
|
||||
hasMarkedText: false
|
||||
)
|
||||
)
|
||||
|
|
@ -2570,7 +2569,6 @@ final class GhosttyMouseFocusTests: XCTestCase {
|
|||
modifierFlags: [.shift],
|
||||
isInsideTmux: false,
|
||||
userConfigDefinesShiftEnterBinding: false,
|
||||
ghosttyHasBinding: false,
|
||||
hasMarkedText: false
|
||||
)
|
||||
)
|
||||
|
|
@ -2581,18 +2579,6 @@ final class GhosttyMouseFocusTests: XCTestCase {
|
|||
modifierFlags: [.shift],
|
||||
isInsideTmux: true,
|
||||
userConfigDefinesShiftEnterBinding: true,
|
||||
ghosttyHasBinding: false,
|
||||
hasMarkedText: false
|
||||
)
|
||||
)
|
||||
|
||||
XCTAssertFalse(
|
||||
GhosttyApp.shouldRemapShiftEnterForTmux(
|
||||
keyCode: 36,
|
||||
modifierFlags: [.shift],
|
||||
isInsideTmux: true,
|
||||
userConfigDefinesShiftEnterBinding: false,
|
||||
ghosttyHasBinding: true,
|
||||
hasMarkedText: false
|
||||
)
|
||||
)
|
||||
|
|
@ -2603,12 +2589,56 @@ final class GhosttyMouseFocusTests: XCTestCase {
|
|||
modifierFlags: [.shift, .command],
|
||||
isInsideTmux: true,
|
||||
userConfigDefinesShiftEnterBinding: false,
|
||||
ghosttyHasBinding: false,
|
||||
hasMarkedText: false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
func testForegroundTmuxProcessOnTTYIsDetected() {
|
||||
let processes = [
|
||||
TerminalSSHSessionDetector.ProcessSnapshot(
|
||||
pid: 47486,
|
||||
pgid: 47486,
|
||||
tpgid: 48365,
|
||||
tty: "ttys089",
|
||||
executableName: "login"
|
||||
),
|
||||
TerminalSSHSessionDetector.ProcessSnapshot(
|
||||
pid: 47487,
|
||||
pgid: 47487,
|
||||
tpgid: 48365,
|
||||
tty: "ttys089",
|
||||
executableName: "zsh"
|
||||
),
|
||||
TerminalSSHSessionDetector.ProcessSnapshot(
|
||||
pid: 48365,
|
||||
pgid: 48365,
|
||||
tpgid: 48365,
|
||||
tty: "ttys089",
|
||||
executableName: "tmux"
|
||||
),
|
||||
]
|
||||
|
||||
XCTAssertTrue(
|
||||
TerminalSSHSessionDetector.isInsideTmuxForTesting(
|
||||
ttyName: "ttys089",
|
||||
processes: processes
|
||||
)
|
||||
)
|
||||
XCTAssertFalse(
|
||||
TerminalSSHSessionDetector.isInsideTmuxForTesting(
|
||||
ttyName: "ttys090",
|
||||
processes: processes
|
||||
)
|
||||
)
|
||||
XCTAssertFalse(
|
||||
TerminalSSHSessionDetector.isInsideTmuxForTesting(
|
||||
ttyName: "ttys089",
|
||||
processes: processes.filter { $0.executableName != "tmux" }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
func testLoadedCJKScanPathsSkipsReleaseAppSupportWhenTaggedConfigExists() throws {
|
||||
let appSupport = FileManager.default.temporaryDirectory
|
||||
.appendingPathComponent("cmux-test-cjk-app-support-\(UUID().uuidString)")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue