Forms: lists reveal their cursor once laid out

- Select, Combobox and MultiSelect opened a long list at its top, the
  choice out of view: gpui skips a scroll asked before the list's first
  frame. Picker and Suggestions share forms::options::reveal, which Popup
  runs from a canvas inside the list
- test: a_long_list_opens_with_its_choice_in_view
- AGENTS: the scroll rule names the reveal
This commit is contained in:
ZacharyZhang-NY committed 2026-09-26 07:25:13 -04:00
1 parent 83e2cdeaa2
commit 6478dc4242
7 files changed
+129 -28

No files matched your search

+10 -15
View File
@@ -7,7 +7,7 @@ use gpui::{
use super::{
Highlight, Input, TextInput,
options::{Choice, Pick, Popup, Run, step},
options::{Choice, Pick, Popup, reveal, step},
text::{Down, Enter, Up},
};
use crate::theme::ActiveTheme;
@@ -151,21 +151,16 @@ impl Suggestions {
let rows: Rc<[Choice]> = self.rows.into();
let shown = open && anchor.is_some();
let highlighted = usable(&rows, picking.read(cx).highlighted);
let revealed = picking.read(cx).revealed.filter(|_| shown);
let stored = (picking.read(cx).highlighted, picking.read(cx).revealed);
if (highlighted, revealed) != stored {
picking.update(cx, |picking, _| {
picking.highlighted = highlighted;
picking.revealed = revealed;
});
if highlighted != picking.read(cx).highlighted {
picking.update(cx, |picking, _| picking.highlighted = highlighted);
}
let reveal = (shown && revealed != Some(highlighted)).then(|| {
let done = picking.clone();
let mark: Run = Rc::new(move |_, cx| {
done.update(cx, |picking, _| picking.revealed = Some(highlighted))
});
(highlighted, mark)
});
let reveal = reveal(
&picking,
|picking| &mut picking.revealed,
shown,
highlighted,
cx,
);
let scroll = picking.read(cx).scroll.clone();
log::debug!(
"suggestions {:?}: open {open}, {} rows, anchor {anchor:?}",