Fix skills picker scrolling in tui app server (#16109)

Fixes #16091.

The app-server TUI was truncating the filtered mention candidate list to
`MAX_POPUP_ROWS`, so the `$` skills picker only exposed the first 8
matches. That made it look like many skills were missing and prevented
keyboard navigation beyond the first page, even though direct
`$skill-name` insertion still worked.

Testing: I manually verified the regression and confirmed the fix.
This commit is contained in:
Eric Traut
2026-03-28 17:22:25 -06:00
committed by GitHub
Unverified
parent f7ef9599ed
commit 46b653e73c
2 changed files with 65 additions and 3 deletions
+22 -3
View File
@@ -180,7 +180,6 @@ impl SkillPopup {
})
});
out.truncate(MAX_POPUP_ROWS);
out
}
}
@@ -235,6 +234,8 @@ fn skill_popup_hint_line() -> Line<'static> {
mod tests {
use super::*;
use pretty_assertions::assert_eq;
use ratatui::buffer::Buffer;
use ratatui::layout::Rect;
fn mention_item(index: usize) -> MentionItem {
MentionItem {
@@ -249,7 +250,7 @@ mod tests {
}
#[test]
fn filtered_mentions_are_capped_to_max_popup_rows() {
fn filtered_mentions_preserve_results_beyond_popup_height() {
let popup = SkillPopup::new((0..(MAX_POPUP_ROWS + 2)).map(mention_item).collect());
let filtered_names: Vec<String> = popup
@@ -260,7 +261,7 @@ mod tests {
assert_eq!(
filtered_names,
(0..MAX_POPUP_ROWS)
(0..(MAX_POPUP_ROWS + 2))
.map(|idx| format!("Mention {idx:02}"))
.collect::<Vec<_>>()
);
@@ -269,4 +270,22 @@ mod tests {
(MAX_POPUP_ROWS as u16) + 2
);
}
fn render_popup(popup: &SkillPopup, width: u16) -> String {
let area = Rect::new(0, 0, width, popup.calculate_required_height(width));
let mut buf = Buffer::empty(area);
popup.render_ref(area, &mut buf);
format!("{buf:?}")
}
#[test]
fn scrolling_mentions_shifts_rendered_window_snapshot() {
let mut popup = SkillPopup::new((0..(MAX_POPUP_ROWS + 2)).map(mention_item).collect());
for _ in 0..=MAX_POPUP_ROWS {
popup.move_down();
}
insta::assert_snapshot!("skill_popup_scrolled", render_popup(&popup, /*width*/ 72));
}
}
@@ -0,0 +1,43 @@
---
source: tui/src/bottom_pane/skill_popup.rs
assertion_line: 289
expression: "render_popup(&popup, /*width*/ 72)"
---
Buffer {
area: Rect { x: 0, y: 0, width: 72, height: 10 },
content: [
" Mention 01 [Skill] Description 01 ",
" Mention 02 [Skill] Description 02 ",
" Mention 03 [Skill] Description 03 ",
" Mention 04 [Skill] Description 04 ",
" Mention 05 [Skill] Description 05 ",
" Mention 06 [Skill] Description 06 ",
" Mention 07 [Skill] Description 07 ",
" Mention 08 [Skill] Description 08 ",
" ",
" Press enter to insert or esc to close ",
],
styles: [
x: 0, y: 0, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 14, y: 0, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
x: 36, y: 0, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 14, y: 1, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
x: 36, y: 1, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 14, y: 2, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
x: 36, y: 2, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 14, y: 3, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
x: 36, y: 3, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 14, y: 4, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
x: 36, y: 4, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 14, y: 5, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
x: 36, y: 5, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 14, y: 6, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
x: 36, y: 6, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 2, y: 7, fg: Cyan, bg: Reset, underline: Reset, modifier: BOLD,
x: 36, y: 7, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 8, y: 9, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
x: 13, y: 9, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 27, y: 9, fg: Reset, bg: Reset, underline: Reset, modifier: DIM,
x: 30, y: 9, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
]
}