diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-06-14 05:30:20 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-06-14 05:30:20 +0300 |
| commit | 226e87306deaba017d36583f51ae34e42b303aad (patch) | |
| tree | 2a1155689b75007c15d93735aedfa58db7a05edf /src/ui | |
| parent | 17544c36ee397233e2f7b3319d86e3b517e3b5d0 (diff) | |
fix: preserve tab identity across restored sessions
Diffstat (limited to 'src/ui')
| -rw-r--r-- | src/ui/mobile.rs | 68 |
1 files changed, 62 insertions, 6 deletions
diff --git a/src/ui/mobile.rs b/src/ui/mobile.rs index b8f23073..a9dc977f 100644 --- a/src/ui/mobile.rs +++ b/src/ui/mobile.rs @@ -290,7 +290,7 @@ fn render_header_status( } else { state_dot(state, seen, p) }; - let tab_label = format!("tab {}/{}", ws.active_tab + 1, ws.tabs.len()); + let tab_label = mobile_tab_status(ws); let row1 = Rect::new(area.x, area.y, area.width, 1); let tab_w = (tab_label.chars().count() as u16 + 1).min(area.width); let name_w = area.width.saturating_sub(tab_w); @@ -329,6 +329,17 @@ fn render_header_status( } } +fn mobile_tab_status(ws: &crate::workspace::Workspace) -> String { + let tab_number = ws + .public_tab_number(ws.active_tab) + .unwrap_or(ws.active_tab + 1); + if ws.tabs.len() <= 1 { + format!("tab {tab_number}") + } else { + format!("tab {tab_number} · {}/{}", ws.active_tab + 1, ws.tabs.len()) + } +} + fn render_switch_button(app: &AppState, frame: &mut Frame, area: Rect) { if area.width == 0 || area.height == 0 { return; @@ -471,10 +482,9 @@ fn render_mobile_switcher_content( ), ]); let detail = format!( - " {} · tab {}/{}", + " {} · {}", ws.branch().unwrap_or_else(|| "shell".into()), - ws.active_tab + 1, - ws.tabs.len() + mobile_tab_status(ws) ); render_two_line_item( frame, @@ -515,9 +525,9 @@ fn render_mobile_switcher_content( let active = idx == ws.active_tab; let bg = mobile_item_bg(false, active, p); let label = if tab.is_auto_named() { - format!("tab {}", idx + 1) + format!("tab {}", tab.display_name()) } else { - format!("{} · {}", idx + 1, tab.display_name()) + format!("{} · {}", tab.number, tab.display_name()) }; let title = Line::from(vec![ Span::styled(" ", Style::default().bg(bg)), @@ -965,6 +975,52 @@ mod tests { assert_eq!(mobile_agent_detail(&entry), " idle · pi"); } + #[test] + fn mobile_tab_status_uses_public_tab_number_and_position() { + let mut workspace = crate::workspace::Workspace::test_new("mobile-tabs"); + let removed_tab = workspace.test_add_tab(None); + workspace.test_add_tab(None); + assert!(workspace.close_tab(removed_tab)); + workspace.active_tab = 1; + + assert_eq!(mobile_tab_status(&workspace), "tab 3 · 2/2"); + } + + #[test] + fn mobile_switcher_uses_stable_public_tab_number_for_auto_tab_labels() { + let mut app = crate::app::state::AppState::test_new(); + let mut workspace = crate::workspace::Workspace::test_new("mobile-tabs"); + let removed_tab = workspace.test_add_tab(None); + workspace.test_add_tab(None); + assert!(workspace.close_tab(removed_tab)); + app.workspaces = vec![workspace]; + app.ensure_test_terminals(); + app.active = Some(0); + app.selected = 0; + app.view.mobile_header_rect = Rect::new(0, 0, 40, 2); + app.view.terminal_area = Rect::new(0, 2, 40, 18); + + let backend = ratatui::backend::TestBackend::new(40, 20); + let mut terminal = ratatui::Terminal::new(backend).unwrap(); + terminal + .draw(|frame| { + render_mobile_panel( + &app, + &TerminalRuntimeRegistry::new(), + frame, + Rect::new(0, 0, 40, 20), + ) + }) + .unwrap(); + + let row = (0..40) + .map(|x| terminal.backend().buffer()[(x, 10)].symbol()) + .collect::<String>(); + + assert!(row.contains("tab 3"), "mobile tab row: {row:?}"); + assert!(!row.contains("tab 2"), "mobile tab row: {row:?}"); + } + #[cfg(unix)] #[tokio::test] async fn mobile_header_uses_live_root_runtime_cwd_for_workspace_label() { |
