diff options
| author | JJ Liebig <jonathan.liebig@gmail.com> | 2026-09-13 20:17:42 +0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-09-13 18:17:42 +0200 |
| commit | 5f26879bcd4190750c79cbff92454e400166ca98 (patch) | |
| tree | 5843579cb70ad81b3dc102294496cdc6868e99da /src/client/shell/tests | |
| parent | 981fe83ca2e23474255f4cacc4da2814f9de0744 (diff) | |
fix(ui): keep muted sidebar and tab labels readable (#4062)
refs #2692
Diffstat (limited to 'src/client/shell/tests')
| -rw-r--r-- | src/client/shell/tests/agents_worktrees_notifications.rs | 61 | ||||
| -rw-r--r-- | src/client/shell/tests/keybindings_settings.rs | 33 | ||||
| -rw-r--r-- | src/client/shell/tests/mod.rs | 35 |
3 files changed, 129 insertions, 0 deletions
diff --git a/src/client/shell/tests/agents_worktrees_notifications.rs b/src/client/shell/tests/agents_worktrees_notifications.rs index fb47ab87..0b936903 100644 --- a/src/client/shell/tests/agents_worktrees_notifications.rs +++ b/src/client/shell/tests/agents_worktrees_notifications.rs @@ -572,6 +572,67 @@ fn agent_sidebar_honors_priority_symbols_tokens_and_stable_hits() { } #[test] +fn muted_agent_sidebar_rows_do_not_stack_terminal_faint() { + let mut projected = snapshot(); + projected.tabs[0].label = "second".into(); + projected.tabs[0].custom_label = true; + projected.agents = vec![ClientShellAgent { + pane_id: "pane_1".into(), + workspace_id: "ws_1".into(), + tab_id: "tab_1".into(), + name: Some("reviewer".into()), + display_agent: None, + agent: Some("pi".into()), + title: None, + terminal_title: None, + terminal_title_stripped: None, + agent_status: AgentStatus::Working, + state_change_seq: 1, + state_labels: Vec::new(), + tokens: Vec::new(), + focused: true, + }]; + let mut state = ClientShellState::new(ClientShellConfig::from_config(&Config::default())); + state.set_snapshot(Box::new(projected)); + state.set_pane_surface(surface()); + let frame = state.compose(106, 30).expect("agent sidebar frame"); + let row = state.hits.agents.first().expect("agent row hit").0; + let buffer = frame.to_ratatui_buffer().expect("agent sidebar buffer"); + + for (label, needle) in [("tab", "second"), ("agent", "reviewer"), ("separator", "ยท")] { + let (x, y) = cell_symbol_position(&frame, row, needle); + let cell = buffer.cell((x, y)).expect("muted sidebar cell"); + assert!( + !cell.modifier.contains(Modifier::DIM), + "{label} cell at ({x},{y}) should not stack terminal faint: {cell:?}" + ); + } +} + +#[test] +fn workspace_state_text_does_not_stack_terminal_faint() { + use crate::config::SpaceSidebarToken; + + let mut config = Config::default(); + config.ui.sidebar.spaces.rows = vec![ + vec![SpaceSidebarToken::StateIcon, SpaceSidebarToken::Workspace], + vec![SpaceSidebarToken::StateText], + ]; + let mut state = ClientShellState::new(ClientShellConfig::from_config(&config)); + state.set_snapshot(Box::new(snapshot())); + state.set_pane_surface(surface()); + let frame = state.compose(106, 30).expect("workspace sidebar frame"); + let rect = state.hits.workspaces.first().expect("workspace hit").rect; + let buffer = frame.to_ratatui_buffer().expect("workspace sidebar buffer"); + let (x, y) = cell_symbol_position(&frame, rect, "idle"); + let cell = buffer.cell((x, y)).expect("workspace state text cell"); + assert!( + !cell.modifier.contains(Modifier::DIM), + "workspace state text at ({x},{y}) should not stack terminal faint: {cell:?}" + ); +} + +#[test] fn active_agent_view_controls_sidebar_order_and_focus_indices() { let mut projected = snapshot(); let mut second_pane = projected.panes[0].clone(); diff --git a/src/client/shell/tests/keybindings_settings.rs b/src/client/shell/tests/keybindings_settings.rs index 1654d0df..e1b43a01 100644 --- a/src/client/shell/tests/keybindings_settings.rs +++ b/src/client/shell/tests/keybindings_settings.rs @@ -165,6 +165,39 @@ fn tab_bar_renders_endpoint_status_ellipses_and_clamps_to_useful_scroll() { } #[test] +fn inactive_auto_named_tab_label_does_not_stack_terminal_faint() { + let mut projected = snapshot(); + projected.tabs.push(ClientShellTab { + tab_id: "tab_2".into(), + workspace_id: "ws_1".into(), + number: 2, + label: "beta".into(), + custom_label: false, + zoomed: false, + focused: false, + agent_status: AgentStatus::Idle, + }); + let mut state = ClientShellState::new(ClientShellConfig::from_config(&Config::default())); + state.set_snapshot(Box::new(projected)); + state.set_pane_surface(surface()); + let frame = state.compose(106, 20).expect("tab bar frame"); + let rect = state + .hits + .tabs + .iter() + .find(|(_, tab_id)| tab_id == "tab_2") + .expect("inactive tab hit") + .0; + let buffer = frame.to_ratatui_buffer().expect("tab bar buffer"); + let (x, y) = cell_symbol_position(&frame, rect, "beta"); + let cell = buffer.cell((x, y)).expect("inactive tab cell"); + assert!( + !cell.modifier.contains(Modifier::DIM), + "inactive tab label at ({x},{y}) should not stack terminal faint: {cell:?}" + ); +} + +#[test] fn configured_prefix_is_client_owned_and_renders_its_bar() { let config = toml::from_str::<Config>( r#" diff --git a/src/client/shell/tests/mod.rs b/src/client/shell/tests/mod.rs index 497ce2c6..a308c1f9 100644 --- a/src/client/shell/tests/mod.rs +++ b/src/client/shell/tests/mod.rs @@ -133,6 +133,41 @@ fn surface() -> PaneSurfaceFrame { } } +fn frame_rows(frame: &FrameData) -> Vec<String> { + frame + .cells + .chunks(frame.width as usize) + .map(|row| row.iter().map(|cell| cell.symbol.as_str()).collect()) + .collect() +} + +/// Absolute cell position of `needle` inside `area`, for style assertions. +fn cell_symbol_position(frame: &FrameData, area: Rect, needle: &str) -> (u16, u16) { + let rows = frame_rows(frame); + for y in area.y..area.bottom().min(frame.height) { + let row = &rows[y as usize]; + let slice = row + .chars() + .skip(area.x as usize) + .take(area.width as usize) + .collect::<String>(); + if let Some(byte) = slice.find(needle) { + let column = slice[..byte].chars().count() as u16 + area.x; + return (column, y); + } + } + let visible = (area.y..area.bottom().min(frame.height)) + .map(|y| { + rows[y as usize] + .chars() + .skip(area.x as usize) + .take(area.width as usize) + .collect::<String>() + }) + .collect::<Vec<_>>(); + panic!("symbol {needle:?} not found in {area:?}: {visible:?}"); +} + fn pane_scroll_result( offset_from_bottom: u64, max_offset_from_bottom: u64, |
