Skip to content

Commit 96284e0

Browse files
committed
fix(cortex-tui): fix scrollbar position to reflect viewport, not selection
The scrollbar in dropdown menus was incorrectly using the selected item index as its position, which caused the scrollbar thumb to jump around based on the highlighted item rather than showing the actual viewport position. This fix changes the scrollbar state to use: - scrollable_range = total_items - max_visible (the actual scrollable area) - position = scroll_offset (the current viewport position) This makes the scrollbar properly indicate which portion of the list is currently visible, so when scrolling past items like /usage, the user can see that there are more items above that are now hidden. Fixed in: - AutocompletePopup (slash commands) - MentionPopup (file mentions) - ScrollableDropdown (generic component) - SelectionList (generic selection) Added max_visible() getter to FileMentionState for proper scrollbar calculation. Fixes scrollbar behavior from PR #216.
1 parent f193b81 commit 96284e0

5 files changed

Lines changed: 24 additions & 10 deletions

File tree

cortex-tui/src/mentions.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,11 @@ impl FileMentionState {
291291
self.scroll_offset
292292
}
293293

294+
/// Returns the maximum visible items.
295+
pub fn max_visible(&self) -> usize {
296+
self.max_visible
297+
}
298+
294299
/// Returns whether there are more items above.
295300
pub fn has_more_above(&self) -> bool {
296301
self.scroll_offset > 0

cortex-tui/src/widgets/autocomplete.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -279,11 +279,12 @@ impl Widget for AutocompletePopup<'_> {
279279
// Render scrollbar if needed
280280
if needs_scrollbar {
281281
// Create scrollbar state
282-
// content_length = total items
283-
// position = selected item for proper thumb position
282+
// content_length = total items minus visible items (scrollable range)
283+
// position = scroll_offset for proper thumb position reflecting viewport
284284
let total_items = self.state.items.len();
285+
let scrollable_range = total_items.saturating_sub(self.state.max_visible);
285286
let mut scrollbar_state =
286-
ScrollbarState::new(total_items).position(self.state.selected);
287+
ScrollbarState::new(scrollable_range).position(self.state.scroll_offset);
287288

288289
// Define scrollbar area (right side of the inner content area)
289290
let scrollbar_area = Rect {

cortex-tui/src/widgets/mention_popup.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,8 +270,11 @@ impl Widget for MentionPopup<'_> {
270270
// Render scrollbar if needed
271271
if needs_scrollbar {
272272
// Create scrollbar state
273+
// content_length = total items minus visible items (scrollable range)
274+
// position = scroll_offset for proper thumb position reflecting viewport
275+
let scrollable_range = total_results.saturating_sub(self.state.max_visible());
273276
let mut scrollbar_state =
274-
ScrollbarState::new(total_results).position(self.state.selected());
277+
ScrollbarState::new(scrollable_range).position(self.state.scroll_offset());
275278

276279
// Define scrollbar area (right side of inner area)
277280
let scrollbar_area = Rect {

cortex-tui/src/widgets/scrollable_dropdown.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -357,10 +357,12 @@ impl<'a> ScrollableDropdown<'a> {
357357
}
358358

359359
// Create scrollbar state
360-
// content_length = total items
361-
// position = selected item (or scroll_offset for better accuracy)
360+
// content_length = total items minus visible items (scrollable range)
361+
// position = scroll_offset for proper thumb position reflecting viewport
362362
let total_items = self.items.len();
363-
let mut scrollbar_state = ScrollbarState::new(total_items).position(self.selected);
363+
let scrollable_range = total_items.saturating_sub(self.max_visible);
364+
let mut scrollbar_state =
365+
ScrollbarState::new(scrollable_range).position(self.scroll_offset);
364366

365367
// Define scrollbar area (right side of the inner content area)
366368
let scrollbar_area = Rect {

cortex-tui/src/widgets/selection_list.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -615,10 +615,13 @@ impl SelectionList {
615615
/// Render scrollbar on the right side.
616616
fn render_scroll_indicators(&self, area: Rect, buf: &mut Buffer) {
617617
// Create scrollbar state
618-
// content_length = total filtered items
619-
// position = selected index for proper thumb position
618+
// content_length = total filtered items minus visible items (scrollable range)
619+
// position = scroll_offset for proper thumb position reflecting viewport
620620
let total_items = self.filtered_indices.len();
621-
let mut scrollbar_state = ScrollbarState::new(total_items).position(self.selected_idx);
621+
let visible_height = area.height as usize;
622+
let scrollable_range = total_items.saturating_sub(visible_height);
623+
let mut scrollbar_state =
624+
ScrollbarState::new(scrollable_range).position(self.scroll_offset);
622625

623626
// Define scrollbar area (right side)
624627
let scrollbar_area = Rect {

0 commit comments

Comments
 (0)