Self-heal tmux attention routing for cmux panes
This commit is contained in:
parent
f0fb098d3b
commit
5cef77e456
4 changed files with 67 additions and 45 deletions
|
|
@ -1864,10 +1864,13 @@ struct CMUXCLI {
|
|||
case "trigger-flash":
|
||||
let tfWsFlag = optionValue(commandArgs, name: "--workspace")
|
||||
let explicitWorkspaceArg = tfWsFlag
|
||||
let callerWorkspaceArg = windowId == nil ? ProcessInfo.processInfo.environment["CMUX_WORKSPACE_ID"] : nil
|
||||
let preferTTYFallback = windowId == nil && ProcessInfo.processInfo.environment["TMUX"] != nil
|
||||
let callerWorkspaceArg = preferTTYFallback
|
||||
? nil
|
||||
: (windowId == nil ? ProcessInfo.processInfo.environment["CMUX_WORKSPACE_ID"] : nil)
|
||||
let workspaceArg = explicitWorkspaceArg ?? callerWorkspaceArg
|
||||
let explicitSurfaceArg = optionValue(commandArgs, name: "--surface") ?? optionValue(commandArgs, name: "--panel")
|
||||
let callerSurfaceArg = explicitWorkspaceArg == nil && windowId == nil
|
||||
let callerSurfaceArg = explicitSurfaceArg == nil && preferTTYFallback == false && windowId == nil
|
||||
? ProcessInfo.processInfo.environment["CMUX_SURFACE_ID"]
|
||||
: nil
|
||||
let surfaceArg = explicitSurfaceArg ?? callerSurfaceArg
|
||||
|
|
@ -2084,10 +2087,13 @@ struct CMUXCLI {
|
|||
let body = optionValue(commandArgs, name: "--body") ?? ""
|
||||
|
||||
let explicitWorkspaceArg = optionValue(commandArgs, name: "--workspace")
|
||||
let callerWorkspaceArg = windowId == nil ? ProcessInfo.processInfo.environment["CMUX_WORKSPACE_ID"] : nil
|
||||
let preferTTYFallback = windowId == nil && ProcessInfo.processInfo.environment["TMUX"] != nil
|
||||
let callerWorkspaceArg = preferTTYFallback
|
||||
? nil
|
||||
: (windowId == nil ? ProcessInfo.processInfo.environment["CMUX_WORKSPACE_ID"] : nil)
|
||||
let workspaceArg = explicitWorkspaceArg ?? callerWorkspaceArg
|
||||
let explicitSurfaceArg = optionValue(commandArgs, name: "--surface")
|
||||
let callerSurfaceArg = explicitWorkspaceArg == nil && windowId == nil
|
||||
let callerSurfaceArg = explicitSurfaceArg == nil && preferTTYFallback == false && windowId == nil
|
||||
? ProcessInfo.processInfo.environment["CMUX_SURFACE_ID"]
|
||||
: nil
|
||||
let surfaceArg = explicitSurfaceArg ?? callerSurfaceArg
|
||||
|
|
|
|||
|
|
@ -76,6 +76,10 @@ _CMUX_TMUX_SYNC_KEYS=(
|
|||
CMUX_TAG
|
||||
CMUX_WORKSPACE_ID
|
||||
)
|
||||
_CMUX_TMUX_SURFACE_SCOPED_KEYS=(
|
||||
CMUX_PANEL_ID
|
||||
CMUX_SURFACE_ID
|
||||
)
|
||||
|
||||
_cmux_tmux_sync_key_is_managed() {
|
||||
local candidate="$1"
|
||||
|
|
@ -116,6 +120,10 @@ _cmux_tmux_publish_cmux_environment() {
|
|||
tmux set-environment -g "$key" "$value" >/dev/null 2>&1 || return 0
|
||||
done
|
||||
|
||||
for key in "${_CMUX_TMUX_SURFACE_SCOPED_KEYS[@]}"; do
|
||||
tmux set-environment -gu "$key" >/dev/null 2>&1 || return 0
|
||||
done
|
||||
|
||||
_CMUX_TMUX_PUSH_SIGNATURE="$signature"
|
||||
}
|
||||
|
||||
|
|
@ -205,17 +213,32 @@ _cmux_git_head_signature() {
|
|||
printf '%s\n' "$line"
|
||||
}
|
||||
|
||||
_cmux_report_tty_payload() {
|
||||
[[ -n "$CMUX_TAB_ID" ]] || return 0
|
||||
[[ -n "$_CMUX_TTY_NAME" ]] || return 0
|
||||
|
||||
local payload="report_tty $_CMUX_TTY_NAME --tab=$CMUX_TAB_ID"
|
||||
if [[ -z "$TMUX" ]]; then
|
||||
[[ -n "$CMUX_PANEL_ID" ]] || return 0
|
||||
payload+=" --panel=$CMUX_PANEL_ID"
|
||||
fi
|
||||
|
||||
printf '%s\n' "$payload"
|
||||
}
|
||||
|
||||
_cmux_report_tty_once() {
|
||||
# Send the TTY name to the app once per session so the batched port scanner
|
||||
# knows which TTY belongs to this panel.
|
||||
(( _CMUX_TTY_REPORTED )) && return 0
|
||||
[[ -S "$CMUX_SOCKET_PATH" ]] || return 0
|
||||
[[ -n "$CMUX_TAB_ID" ]] || return 0
|
||||
[[ -n "$CMUX_PANEL_ID" ]] || return 0
|
||||
[[ -n "$_CMUX_TTY_NAME" ]] || return 0
|
||||
|
||||
local payload=""
|
||||
payload="$(_cmux_report_tty_payload)"
|
||||
[[ -n "$payload" ]] || return 0
|
||||
|
||||
_CMUX_TTY_REPORTED=1
|
||||
{
|
||||
_cmux_send "report_tty $_CMUX_TTY_NAME --tab=$CMUX_TAB_ID --panel=$CMUX_PANEL_ID"
|
||||
_cmux_send "$payload"
|
||||
} >/dev/null 2>&1 & disown
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -82,6 +82,10 @@ typeset -ga _CMUX_TMUX_SYNC_KEYS=(
|
|||
CMUX_TAG
|
||||
CMUX_WORKSPACE_ID
|
||||
)
|
||||
typeset -ga _CMUX_TMUX_SURFACE_SCOPED_KEYS=(
|
||||
CMUX_PANEL_ID
|
||||
CMUX_SURFACE_ID
|
||||
)
|
||||
|
||||
_cmux_tmux_sync_key_is_managed() {
|
||||
local candidate="$1"
|
||||
|
|
@ -119,6 +123,10 @@ _cmux_tmux_publish_cmux_environment() {
|
|||
tmux set-environment -g "$key" "$value" >/dev/null 2>&1 || return 0
|
||||
done
|
||||
|
||||
for key in "${_CMUX_TMUX_SURFACE_SCOPED_KEYS[@]}"; do
|
||||
tmux set-environment -gu "$key" >/dev/null 2>&1 || return 0
|
||||
done
|
||||
|
||||
_CMUX_TMUX_PUSH_SIGNATURE="$signature"
|
||||
}
|
||||
|
||||
|
|
@ -305,17 +313,32 @@ _cmux_git_head_signature() {
|
|||
return 1
|
||||
}
|
||||
|
||||
_cmux_report_tty_payload() {
|
||||
[[ -n "$CMUX_TAB_ID" ]] || return 0
|
||||
[[ -n "$_CMUX_TTY_NAME" ]] || return 0
|
||||
|
||||
local payload="report_tty $_CMUX_TTY_NAME --tab=$CMUX_TAB_ID"
|
||||
if [[ -z "$TMUX" ]]; then
|
||||
[[ -n "$CMUX_PANEL_ID" ]] || return 0
|
||||
payload+=" --panel=$CMUX_PANEL_ID"
|
||||
fi
|
||||
|
||||
print -r -- "$payload"
|
||||
}
|
||||
|
||||
_cmux_report_tty_once() {
|
||||
# Send the TTY name to the app once per session so the batched port scanner
|
||||
# knows which TTY belongs to this panel.
|
||||
(( _CMUX_TTY_REPORTED )) && return 0
|
||||
[[ -S "$CMUX_SOCKET_PATH" ]] || return 0
|
||||
[[ -n "$CMUX_TAB_ID" ]] || return 0
|
||||
[[ -n "$CMUX_PANEL_ID" ]] || return 0
|
||||
[[ -n "$_CMUX_TTY_NAME" ]] || return 0
|
||||
|
||||
local payload=""
|
||||
payload="$(_cmux_report_tty_payload)"
|
||||
[[ -n "$payload" ]] || return 0
|
||||
|
||||
_CMUX_TTY_REPORTED=1
|
||||
{
|
||||
_cmux_send "report_tty $_CMUX_TTY_NAME --tab=$CMUX_TAB_ID --panel=$CMUX_PANEL_ID"
|
||||
_cmux_send "$payload"
|
||||
} >/dev/null 2>&1 &!
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2526,51 +2526,21 @@ final class ZshShellIntegrationHandoffTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testShellIntegrationReportsTTYFromTmuxWithoutUsingPanelScope() throws {
|
||||
let fileManager = FileManager.default
|
||||
let root = fileManager.temporaryDirectory
|
||||
.appendingPathComponent("cmux-zsh-tmux-report-tty-\(UUID().uuidString)")
|
||||
let binDir = root.appendingPathComponent("bin", isDirectory: true)
|
||||
let socketPath = root.appendingPathComponent("cmux-test.sock", isDirectory: false)
|
||||
let logPath = root.appendingPathComponent("tty.log", isDirectory: false)
|
||||
|
||||
try fileManager.createDirectory(at: root, withIntermediateDirectories: true)
|
||||
try fileManager.createDirectory(at: binDir, withIntermediateDirectories: true)
|
||||
let listenerFD = try bindUnixSocket(at: socketPath.path)
|
||||
defer {
|
||||
Darwin.close(listenerFD)
|
||||
unlink(socketPath.path)
|
||||
try? fileManager.removeItem(at: root)
|
||||
}
|
||||
|
||||
try writeExecutableScript(
|
||||
at: binDir.appendingPathComponent("ncat", isDirectory: false),
|
||||
contents: """
|
||||
#!/bin/sh
|
||||
cat > "\(logPath.path)"
|
||||
exit 0
|
||||
"""
|
||||
)
|
||||
|
||||
_ = try runInteractiveZsh(
|
||||
let output = try runInteractiveZsh(
|
||||
cmuxLoadGhosttyIntegration: false,
|
||||
cmuxLoadShellIntegration: true,
|
||||
command: """
|
||||
_CMUX_TTY_NAME=ttys999
|
||||
_cmux_report_tty_once
|
||||
sleep 0.05
|
||||
print -r -- READY
|
||||
print -r -- "$(_cmux_report_tty_payload)"
|
||||
""",
|
||||
extraEnvironment: [
|
||||
"PATH": "\(binDir.path):/usr/bin:/bin:/usr/sbin:/sbin",
|
||||
"TMUX": "/tmp/tmux-current,123,0",
|
||||
"CMUX_SOCKET_PATH": socketPath.path,
|
||||
"CMUX_TAB_ID": "11111111-1111-1111-1111-111111111111",
|
||||
"CMUX_PANEL_ID": "99999999-9999-9999-9999-999999999999",
|
||||
]
|
||||
)
|
||||
|
||||
let log = (try? String(contentsOf: logPath, encoding: .utf8)) ?? ""
|
||||
XCTAssertEqual(log, "report_tty ttys999 --tab=11111111-1111-1111-1111-111111111111\n")
|
||||
XCTAssertEqual(output, "report_tty ttys999 --tab=11111111-1111-1111-1111-111111111111")
|
||||
}
|
||||
|
||||
private func runInteractiveZsh(cmuxLoadGhosttyIntegration: Bool) throws -> String {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue