From 0ff0f27e222633c97ba4291f6b9be4137002ca84 Mon Sep 17 00:00:00 2001 From: Can Celik Date: Mon, 21 Sep 2026 00:29:45 +0300 Subject: fix: preserve session layouts across shutdown and restore failures (#4400) * fix: preserve session layouts across shutdown and restore failures refs #4320 * test: update subscription fixture for pane restore errors --------- Co-authored-by: JJ Liebig --- src/ui/panes.rs | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) (limited to 'src/ui') diff --git a/src/ui/panes.rs b/src/ui/panes.rs index ab3e352a..be9df8da 100644 --- a/src/ui/panes.rs +++ b/src/ui/panes.rs @@ -2,7 +2,7 @@ use ratatui::{ buffer::Buffer, layout::Rect, style::{Color, Modifier, Style}, - widgets::{Block, Borders}, + widgets::{Block, Borders, Paragraph, Wrap}, Frame, }; @@ -392,9 +392,10 @@ pub(super) fn render_panes( pane_infos: &[PaneInfo], split_borders: &[crate::layout::SplitBorder], ) { - let Some(ws_idx) = target.map(|target| target.workspace_index) else { + let Some(target) = target else { return; }; + let ws_idx = target.workspace_index; let Some(ws) = app.workspaces.get(ws_idx) else { return; }; @@ -406,6 +407,17 @@ pub(super) fn render_panes( && app.pane_exposes_host_cursor(ws_idx, info.id); rt.render(frame, info.inner_rect, show_cursor); render_pane_scrollbar(app, frame, info, rt); + } else if let Some(reason) = ws + .tabs + .get(target.tab_index) + .and_then(|tab| tab.terminal_id(info.id)) + .and_then(|id| app.terminals.get(id)) + .and_then(|terminal| terminal.restore_error.as_deref()) + { + frame.render_widget( + Paragraph::new(reason).wrap(Wrap { trim: false }), + info.inner_rect, + ); } } @@ -847,6 +859,32 @@ mod tests { render_pane_borders(app, ws, &app.view.pane_infos, split_borders, frame); } + #[test] + fn unavailable_pane_renders_restore_failure_without_a_runtime() { + let mut app = AppState::test_new(); + app.workspaces = vec![Workspace::test_new("unavailable")]; + app.active = Some(0); + app.ensure_test_terminals(); + let pane_id = app.workspaces[0].tabs[0].root_pane; + let terminal_id = app.workspaces[0].terminal_id(pane_id).unwrap().clone(); + app.terminals.get_mut(&terminal_id).unwrap().restore_error = + Some("Saved directory is unavailable. Restart to retry.".into()); + let (buffer, cursor, _, _) = crate::server::render_stream::render_tab_surface_virtual( + &app, + &TerminalRuntimeRegistry::new(), + Some(crate::ui::TabSurfaceTarget { + workspace_index: 0, + tab_index: 0, + }), + Rect::new(0, 0, 80, 24), + false, + Default::default(), + ); + let text: String = buffer.content.iter().map(|cell| cell.symbol()).collect(); + assert!(text.contains("Saved directory is unavailable.")); + assert!(cursor.is_none_or(|cursor| !cursor.visible)); + } + #[test] fn pane_border_title_trims_and_truncates() { assert_eq!( -- cgit v1.2.3