diff options
| author | akbash <akbash@herdr.dev> | 2026-09-15 04:20:59 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-09-15 03:20:59 +0200 |
| commit | 052779c4159ed851ae78ed1271130811986d1166 (patch) | |
| tree | 7b3cb372966549abf5cb41a96952997eda1304c9 /src/client/shell/tabs.rs | |
| parent | 32503f81f7f22552d86f048afb3de179f44e049a (diff) | |
fix: reveal the full last tab in overflowing tab strips (#4152)
refs #4151
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Diffstat (limited to 'src/client/shell/tabs.rs')
| -rw-r--r-- | src/client/shell/tabs.rs | 56 |
1 files changed, 39 insertions, 17 deletions
diff --git a/src/client/shell/tabs.rs b/src/client/shell/tabs.rs index 9e9901ff..3fdcf7dc 100644 --- a/src/client/shell/tabs.rs +++ b/src/client/shell/tabs.rs @@ -134,7 +134,7 @@ pub(crate) fn render_tab_bar( if overflow && mouse_chrome { hits.tab_scroll_right = Rect::new(tab_right, area.y, TAB_SCROLL_BUTTON_WIDTH, 1); - let can_scroll_right = last_visible.is_some_and(|index| index + 1 < tabs.len()); + let can_scroll_right = *tab_scroll < max_scroll; put_text( buffer, hits.tab_scroll_right.x, @@ -353,25 +353,22 @@ fn centered_tab_scroll(focused: usize, widths: &[u16], available: u16) -> usize } fn max_tab_scroll(widths: &[u16], available: u16) -> usize { - (0..widths.len()) - .find(|start| last_visible_tab(*start, widths, available) == widths.len().checked_sub(1)) - .unwrap_or(0) -} - -fn last_visible_tab(start: usize, widths: &[u16], available: u16) -> Option<usize> { - let mut remaining = available; - let mut last = None; - for (index, width) in widths.iter().copied().enumerate().skip(start) { - if remaining == 0 { - break; - } - last = Some(index); - if width >= remaining { + let Some((&last, preceding)) = widths.split_last() else { + return 0; + }; + let mut start = preceding.len(); + let mut used = u32::from(last); + // Keep the longest fully visible suffix, not merely a sliver of the last tab. + // An oversized last tab must still be reachable at the start of the strip. + for width in preceding.iter().rev() { + let required = used + 1 + u32::from(*width); + if required > u32::from(available) { break; } - remaining = remaining.saturating_sub(width.saturating_add(1)); + used = required; + start -= 1; } - last + start } fn tab_label(tab: &ClientShellTab) -> String { @@ -381,3 +378,28 @@ fn tab_label(tab: &ClientShellTab) -> String { tab.label.clone() } } + +#[cfg(test)] +mod tests { + use super::max_tab_scroll; + + #[test] + fn trailing_scroll_limit_accounts_for_full_widths_and_separators() { + for (widths, available, expected) in [ + (&[][..], 0, 0), + (&[8, 13][..], 0, 1), + (&[8, 13][..], 1, 1), + (&[8, 13][..], 12, 1), + (&[8, 13][..], 21, 1), + (&[8, 13][..], 22, 0), + (&[8, 13][..], 30, 0), + (&[8, u16::MAX][..], u16::MAX, 1), + ] { + assert_eq!( + max_tab_scroll(widths, available), + expected, + "widths={widths:?}, available={available}" + ); + } + } +} |
