aboutsummaryrefslogtreecommitdiff
path: root/src/client
diff options
context:
space:
mode:
authorCan Celik <ogulcancelik@gmail.com>2026-08-15 15:03:59 +0300
committerGitHub <noreply@github.com>2026-08-15 15:03:59 +0300
commitb660cad80450147610091e0e5758faa6276e5983 (patch)
tree5896dce7455f69199447520c19a40af5472e436a /src/client
parent9e6c2b4e0957498b7da884ed2789fe28b9cde9cf (diff)
fix(client): handle remote terminal hangup (#2827)
refs #2424
Diffstat (limited to 'src/client')
-rw-r--r--src/client/mod.rs46
1 files changed, 34 insertions, 12 deletions
diff --git a/src/client/mod.rs b/src/client/mod.rs
index cba735fa..b70b6c9c 100644
--- a/src/client/mod.rs
+++ b/src/client/mod.rs
@@ -421,6 +421,7 @@ fn setup_terminal_with_capabilities(
Ok(TerminalGuard {
reset_modify_other_keys: modify_other_keys_mode.is_some(),
reset_host_color_scheme_reports: host_color_scheme_reports,
+ restored: false,
#[cfg(windows)]
restore_windows_input_mode: windows_virtual_terminal_input.restore_mode,
})
@@ -434,6 +435,7 @@ fn should_enable_host_color_scheme_reports(enable_client_protocols: bool) -> boo
struct TerminalGuard {
reset_modify_other_keys: bool,
reset_host_color_scheme_reports: bool,
+ restored: bool,
#[cfg(windows)]
restore_windows_input_mode: Option<u32>,
}
@@ -582,7 +584,7 @@ fn restore_terminal_state(
reset_modify_other_keys: bool,
reset_host_color_scheme_reports: bool,
#[cfg(windows)] restore_windows_input_mode: Option<u32>,
-) {
+) -> io::Result<()> {
let _ = clear_received_kitty_graphics(&mut io::stdout());
// Reset modifyOtherKeys if we enabled it.
@@ -606,13 +608,16 @@ fn restore_terminal_state(
restore_windows_input_mode_value(mode);
}
- let _ = ratatui::try_restore();
- let _ = write_terminal_restore_postlude(&mut io::stdout(), reset_host_color_scheme_reports);
+ let restore_result = ratatui::try_restore();
+ let postlude_result =
+ write_terminal_restore_postlude(&mut io::stdout(), reset_host_color_scheme_reports);
#[cfg(windows)]
if windows_vti_input_backend_enabled() && windows_win32_input_mode_enabled() {
let _ = disable_windows_win32_input_mode(&mut io::stdout());
}
+
+ restore_result.and(postlude_result)
}
#[cfg(not(windows))]
@@ -657,14 +662,28 @@ fn disable_windows_win32_input_mode(writer: &mut impl std::io::Write) -> io::Res
writer.flush()
}
-impl Drop for TerminalGuard {
- fn drop(&mut self) {
+impl TerminalGuard {
+ fn restore(mut self) -> io::Result<()> {
+ self.restored = true;
restore_terminal_state(
self.reset_modify_other_keys,
self.reset_host_color_scheme_reports,
#[cfg(windows)]
self.restore_windows_input_mode,
- );
+ )
+ }
+}
+
+impl Drop for TerminalGuard {
+ fn drop(&mut self) {
+ if !self.restored {
+ let _ = restore_terminal_state(
+ self.reset_modify_other_keys,
+ self.reset_host_color_scheme_reports,
+ #[cfg(windows)]
+ self.restore_windows_input_mode,
+ );
+ }
}
}
@@ -1281,7 +1300,7 @@ fn run_client_with_mode(
let panic_restore_windows_input_mode = terminal_guard.restore_windows_input_mode;
let original_hook = std::panic::take_hook();
std::panic::set_hook(Box::new(move |info| {
- restore_terminal_state(
+ let _ = restore_terminal_state(
panic_resets_modify_other_keys,
panic_resets_host_color_scheme_reports,
#[cfg(windows)]
@@ -1323,19 +1342,22 @@ fn run_client_with_mode(
});
// Restore the terminal before printing any final status message.
- drop(terminal_guard);
+ let terminal_restore_failed = terminal_guard.restore().is_err();
if let Err(err) = result {
- eprintln!("herdr: {err}");
+ let _ = writeln!(io::stderr(), "herdr: {err}");
rt.shutdown_timeout(Duration::from_millis(100));
crate::logging::shutdown("client");
- if matches!(
- err,
+ let detached = matches!(
+ &err,
ClientError::ServerShutdown {
reason: Some(reason)
} if reason == "detached"
- ) {
+ );
+ let connection_lost_during_terminal_hangup =
+ terminal_restore_failed && matches!(&err, ClientError::ConnectionLost(_));
+ if detached || connection_lost_during_terminal_hangup {
return Ok(());
}