Fix Shift+Enter tmux follow-up regressions
This commit is contained in:
parent
9080248393
commit
9ce4997ced
4 changed files with 106 additions and 14 deletions
|
|
@ -61,7 +61,7 @@ _CMUX_ASYNC_JOB_TIMEOUT="${_CMUX_ASYNC_JOB_TIMEOUT:-20}"
|
|||
|
||||
_CMUX_PORTS_LAST_RUN="${_CMUX_PORTS_LAST_RUN:-0}"
|
||||
_CMUX_SHELL_ACTIVITY_LAST="${_CMUX_SHELL_ACTIVITY_LAST:-}"
|
||||
_CMUX_TMUX_STATE_LAST="${_CMUX_TMUX_STATE_LAST:-}"
|
||||
_CMUX_TMUX_STATE_SIGNATURE_LAST="${_CMUX_TMUX_STATE_SIGNATURE_LAST:-}"
|
||||
_CMUX_TTY_NAME="${_CMUX_TTY_NAME:-}"
|
||||
_CMUX_TTY_REPORTED="${_CMUX_TTY_REPORTED:-0}"
|
||||
_CMUX_TMUX_PUSH_SIGNATURE="${_CMUX_TMUX_PUSH_SIGNATURE:-}"
|
||||
|
|
@ -275,6 +275,13 @@ _cmux_report_tmux_state_payload() {
|
|||
printf '%s\n' "report_tmux_state $state --tab=$CMUX_TAB_ID --panel=$CMUX_PANEL_ID"
|
||||
}
|
||||
|
||||
_cmux_tmux_state_report_signature() {
|
||||
local payload="$1"
|
||||
[[ -n "$payload" ]] || return 0
|
||||
[[ -n "$CMUX_SOCKET_PATH" ]] || return 0
|
||||
printf '%s\037%s\n' "$CMUX_SOCKET_PATH" "$payload"
|
||||
}
|
||||
|
||||
_cmux_report_tmux_state() {
|
||||
[[ -S "$CMUX_SOCKET_PATH" ]] || return 0
|
||||
|
||||
|
|
@ -282,10 +289,11 @@ _cmux_report_tmux_state() {
|
|||
payload="$(_cmux_report_tmux_state_payload)"
|
||||
[[ -n "$payload" ]] || return 0
|
||||
|
||||
local state="${payload#report_tmux_state }"
|
||||
state="${state%% *}"
|
||||
[[ "$_CMUX_TMUX_STATE_LAST" == "$state" ]] && return 0
|
||||
_CMUX_TMUX_STATE_LAST="$state"
|
||||
local signature=""
|
||||
signature="$(_cmux_tmux_state_report_signature "$payload")"
|
||||
[[ -n "$signature" ]] || return 0
|
||||
[[ "$_CMUX_TMUX_STATE_SIGNATURE_LAST" == "$signature" ]] && return 0
|
||||
_CMUX_TMUX_STATE_SIGNATURE_LAST="$signature"
|
||||
{
|
||||
_cmux_send "$payload"
|
||||
} >/dev/null 2>&1 & disown
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ typeset -g _CMUX_ASYNC_JOB_TIMEOUT=20
|
|||
typeset -g _CMUX_PORTS_LAST_RUN=0
|
||||
typeset -g _CMUX_CMD_START=0
|
||||
typeset -g _CMUX_SHELL_ACTIVITY_LAST=""
|
||||
typeset -g _CMUX_TMUX_STATE_LAST=""
|
||||
typeset -g _CMUX_TMUX_STATE_SIGNATURE_LAST=""
|
||||
typeset -g _CMUX_TTY_NAME=""
|
||||
typeset -g _CMUX_TTY_REPORTED=0
|
||||
typeset -g _CMUX_GHOSTTY_SEMANTIC_PATCHED=0
|
||||
|
|
@ -380,6 +380,13 @@ _cmux_report_tmux_state_payload() {
|
|||
print -r -- "report_tmux_state $state --tab=$CMUX_TAB_ID --panel=$CMUX_PANEL_ID"
|
||||
}
|
||||
|
||||
_cmux_tmux_state_report_signature() {
|
||||
local payload="$1"
|
||||
[[ -n "$payload" ]] || return 0
|
||||
[[ -n "$CMUX_SOCKET_PATH" ]] || return 0
|
||||
print -r -- "${CMUX_SOCKET_PATH}"$'\x1f'"${payload}"
|
||||
}
|
||||
|
||||
_cmux_report_tmux_state() {
|
||||
[[ -S "$CMUX_SOCKET_PATH" ]] || return 0
|
||||
|
||||
|
|
@ -387,10 +394,11 @@ _cmux_report_tmux_state() {
|
|||
payload="$(_cmux_report_tmux_state_payload)"
|
||||
[[ -n "$payload" ]] || return 0
|
||||
|
||||
local state="${payload#report_tmux_state }"
|
||||
state="${state%% *}"
|
||||
[[ "$_CMUX_TMUX_STATE_LAST" == "$state" ]] && return 0
|
||||
_CMUX_TMUX_STATE_LAST="$state"
|
||||
local signature=""
|
||||
signature="$(_cmux_tmux_state_report_signature "$payload")"
|
||||
[[ -n "$signature" ]] || return 0
|
||||
[[ "$_CMUX_TMUX_STATE_SIGNATURE_LAST" == "$signature" ]] && return 0
|
||||
_CMUX_TMUX_STATE_SIGNATURE_LAST="$signature"
|
||||
_cmux_send_bg "$payload"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1672,6 +1672,11 @@ class GhosttyApp {
|
|||
var containsExplicitShiftEnterDirective = false
|
||||
|
||||
mutating func recordKeybind(_ value: String) {
|
||||
let trimmed = value.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
|
||||
if trimmed.isEmpty || trimmed == "clear" {
|
||||
containsExplicitShiftEnterDirective = false
|
||||
return
|
||||
}
|
||||
if GhosttyApp.keybindDirectiveTargetsShiftEnter(value) {
|
||||
containsExplicitShiftEnterDirective = true
|
||||
}
|
||||
|
|
@ -1694,7 +1699,7 @@ class GhosttyApp {
|
|||
|
||||
var loadedRecursivePaths = Set<String>()
|
||||
var index = 0
|
||||
while index < recursiveConfigPaths.count && !summary.containsExplicitShiftEnterDirective {
|
||||
while index < recursiveConfigPaths.count {
|
||||
let path = NSString(string: recursiveConfigPaths[index]).expandingTildeInPath
|
||||
index += 1
|
||||
|
||||
|
|
@ -1814,9 +1819,6 @@ class GhosttyApp {
|
|||
case "keybind":
|
||||
guard let value = entry.value else { continue }
|
||||
summary.recordKeybind(value)
|
||||
if summary.containsExplicitShiftEnterDirective {
|
||||
return
|
||||
}
|
||||
case "config-file":
|
||||
guard let value = entry.value else { continue }
|
||||
applyConfigFileDirective(
|
||||
|
|
|
|||
|
|
@ -2522,6 +2522,28 @@ final class GhosttyMouseFocusTests: XCTestCase {
|
|||
)
|
||||
}
|
||||
|
||||
func testUserConfigDefinesShiftEnterBindingHonorsLaterClearInIncludedFile() throws {
|
||||
let dir = FileManager.default.temporaryDirectory
|
||||
.appendingPathComponent("cmux-test-shift-enter-clear-\(UUID().uuidString)")
|
||||
try FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
|
||||
defer { try? FileManager.default.removeItem(at: dir) }
|
||||
|
||||
let included = dir.appendingPathComponent("bindings.conf")
|
||||
try "keybind = clear\n"
|
||||
.write(to: included, atomically: true, encoding: .utf8)
|
||||
|
||||
let main = dir.appendingPathComponent("config")
|
||||
try """
|
||||
keybind = shift+enter=text:\\x0a
|
||||
config-file = \(included.path)
|
||||
"""
|
||||
.write(to: main, atomically: true, encoding: .utf8)
|
||||
|
||||
XCTAssertFalse(
|
||||
GhosttyApp.userConfigDefinesShiftEnterBinding(configPaths: [main.path])
|
||||
)
|
||||
}
|
||||
|
||||
func testUserConfigDefinesShiftEnterBindingIgnoresOtherModifierCombinations() throws {
|
||||
try withTempConfig("keybind = cmd+shift+enter=text:\\x0a\n") { path in
|
||||
XCTAssertFalse(
|
||||
|
|
@ -2993,6 +3015,58 @@ final class ZshShellIntegrationHandoffTests: XCTestCase {
|
|||
)
|
||||
}
|
||||
|
||||
func testShellIntegrationResendsTmuxStateWhenSocketTargetChanges() throws {
|
||||
let fileManager = FileManager.default
|
||||
let root = fileManager.temporaryDirectory
|
||||
.appendingPathComponent("cmux-zsh-tmux-state-resend-\(UUID().uuidString)")
|
||||
try fileManager.createDirectory(at: root, withIntermediateDirectories: true)
|
||||
defer { try? fileManager.removeItem(at: root) }
|
||||
|
||||
let socketA = root.appendingPathComponent("cmux-a.sock").path
|
||||
let socketB = root.appendingPathComponent("cmux-b.sock").path
|
||||
|
||||
let output = try runInteractiveZsh(
|
||||
cmuxLoadGhosttyIntegration: false,
|
||||
cmuxLoadShellIntegration: true,
|
||||
command: """
|
||||
python3 -c 'import os, socket, sys, time; path = sys.argv[1]; \
|
||||
os.path.exists(path) and os.unlink(path); \
|
||||
s = socket.socket(socket.AF_UNIX); s.bind(path); s.listen(1); time.sleep(3)' "$CMUX_SOCKET_PATH" &
|
||||
server_a=$!
|
||||
sleep 0.1
|
||||
functions[_cmux_send_bg]='print -r -- "$1"'
|
||||
_CMUX_TMUX_STATE_SIGNATURE_LAST=""
|
||||
_cmux_report_tmux_state
|
||||
kill $server_a >/dev/null 2>&1
|
||||
wait $server_a >/dev/null 2>&1
|
||||
|
||||
export CMUX_SOCKET_PATH="\(socketB)"
|
||||
python3 -c 'import os, socket, sys, time; path = sys.argv[1]; \
|
||||
os.path.exists(path) and os.unlink(path); \
|
||||
s = socket.socket(socket.AF_UNIX); s.bind(path); s.listen(1); time.sleep(3)' "$CMUX_SOCKET_PATH" &
|
||||
server_b=$!
|
||||
sleep 0.1
|
||||
_cmux_report_tmux_state
|
||||
kill $server_b >/dev/null 2>&1
|
||||
wait $server_b >/dev/null 2>&1
|
||||
""",
|
||||
extraEnvironment: [
|
||||
"TMUX": "/tmp/tmux-current,123,0",
|
||||
"CMUX_SOCKET_PATH": socketA,
|
||||
"CMUX_TAB_ID": "11111111-1111-1111-1111-111111111111",
|
||||
"CMUX_PANEL_ID": "99999999-9999-9999-9999-999999999999",
|
||||
]
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
output,
|
||||
"""
|
||||
report_tmux_state inside --tab=11111111-1111-1111-1111-111111111111 --panel=99999999-9999-9999-9999-999999999999
|
||||
report_tmux_state inside --tab=11111111-1111-1111-1111-111111111111 --panel=99999999-9999-9999-9999-999999999999
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
private func runInteractiveZsh(cmuxLoadGhosttyIntegration: Bool) throws -> String {
|
||||
try runInteractiveZsh(
|
||||
cmuxLoadGhosttyIntegration: cmuxLoadGhosttyIntegration,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue