diff --git a/pyproject.toml b/pyproject.toml index fc548a5..cd70406 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "sessions-sublime" -version = "0.7.41" +version = "0.7.42" description = "Sublime-facing Python code for Sessions." requires-python = ">=3.8" license = {text = "MIT"} diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 097c1fa..0f0da79 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -221,7 +221,7 @@ checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "local_bridge" -version = "0.7.41" +version = "0.7.42" dependencies = [ "base64", "glob", @@ -432,7 +432,7 @@ dependencies = [ [[package]] name = "session_helper" -version = "0.7.41" +version = "0.7.42" dependencies = [ "base64", "notify", @@ -443,7 +443,7 @@ dependencies = [ [[package]] name = "session_protocol" -version = "0.7.41" +version = "0.7.42" dependencies = [ "base64", "serde", @@ -452,14 +452,14 @@ dependencies = [ [[package]] name = "sessions_askpass" -version = "0.7.41" +version = "0.7.42" dependencies = [ "tempfile", ] [[package]] name = "sessions_native" -version = "0.7.41" +version = "0.7.42" dependencies = [ "base64", "notify", @@ -773,7 +773,7 @@ dependencies = [ [[package]] name = "workspace_identity" -version = "0.7.41" +version = "0.7.42" [[package]] name = "zmij" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 6d241d3..db6c834 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -12,7 +12,7 @@ resolver = "2" [workspace.package] edition = "2024" license = "MIT" -version = "0.7.41" +version = "0.7.42" authors = ["Myeongseon Choi "] repository = "https://git.teahaven.kr/sublime-rs/sessions" homepage = "https://git.teahaven.kr/sublime-rs/sessions" diff --git a/rust/crates/local_bridge/src/main.rs b/rust/crates/local_bridge/src/main.rs index 4a79102..750e9a3 100644 --- a/rust/crates/local_bridge/src/main.rs +++ b/rust/crates/local_bridge/src/main.rs @@ -49,7 +49,12 @@ fn main() { .map(String::as_str) .is_some_and(|first| matches!(first, "--version" | "-V" | "version")) { - println!("{LOCAL_BRIDGE_VERSION_BANNER}"); + // Use ``writeln!`` + ``let _`` so EPIPE silently fails through to + // ``return`` instead of panicking → SIGABRT under + // ``panic = "abort"``. Same rationale as the eprintln sites + // hardened in v0.7.39 (b44f708): a parent that closes its end of + // our stdout before we write must not generate a phantom crash. + let _ = writeln!(std::io::stdout(), "{LOCAL_BRIDGE_VERSION_BANNER}"); return; } if args.first().map(String::as_str) == Some("lsp-stdio") { @@ -68,7 +73,16 @@ fn main() { match run(&args) { Ok(output) => match serde_json::to_string(&output) { Ok(encoded) => { - println!("{encoded}"); + // ``writeln!`` + ``let _`` here for the same reason as the + // eprintln sites hardened in v0.7.39: when Sublime / the + // Python ctypes parent dies first the bridge inherits a + // broken stdout pipe, and a bare ``println!`` panics on + // EPIPE → SIGABRT under ``panic = "abort"``. The earlier + // pass only covered stderr; this is the missed stdout + // site that produced the + // ``local_bridge::main hf88e153b048e40f5 main.rs:71`` + // abort signature in user crash reports. + let _ = writeln!(std::io::stdout(), "{encoded}"); } Err(error) => { let _ = writeln!( diff --git a/sublime/sessions/commands.py b/sublime/sessions/commands.py index 632956e..53b756c 100644 --- a/sublime/sessions/commands.py +++ b/sublime/sessions/commands.py @@ -6952,9 +6952,16 @@ class SessionsOpenRemoteTerminalCommand(sublime_plugin.WindowCommand): # out to break interactive zsh on some macOS → Linux setups # ("zsh: bad option: -/") — dropped in v0.7.30.5. ``ssh -t`` # already allocates a pty so the redirections were redundant. - remote_invocation = "cd {}; exec ${{SHELL:-/bin/sh}} -il".format( - shlex.quote(remote_root) - ) + # + # ``"$SHELL"`` not ``${SHELL:-/bin/sh}``: the ``:-`` fallback + # form re-tripped some zsh setups in v0.7.31+ with + # ``zsh:1: unknown exec flag -/`` — the parameter expansion + # split such that the literal ``-/bin/sh`` reached ``exec`` as + # a flag instead of expanding to ``/bin/sh``. sshd populates + # ``$SHELL`` from the user's passwd entry in every login + # session, so the fallback was redundant; quoting ``"$SHELL"`` + # also handles the rare path-with-spaces case. + remote_invocation = 'cd {}; exec "$SHELL" -il'.format(shlex.quote(remote_root)) # ``panel_name`` makes Terminus open the shell as a panel # docked at the bottom of the active window. Without it # Terminus defaults to a new tab in the editor pane group, diff --git a/sublime/tests/test_cmd_connect.py b/sublime/tests/test_cmd_connect.py index 4cbb91a..aafc9bc 100644 --- a/sublime/tests/test_cmd_connect.py +++ b/sublime/tests/test_cmd_connect.py @@ -450,12 +450,15 @@ def test_open_remote_terminal_opens_transient_terminus_pane( # handshake is racy. ``;`` not ``&&`` so a failed ``cd`` doesn't # take the shell down with it. The earlier ``