From ff15ddf3e0c65a6ab565c76e4a87e6376266589e Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Thu, 9 Nov 2023 16:36:36 -0700 Subject: [PATCH] Render more than one item --- .../command_palette2/src/command_palette.rs | 67 ++++----------- crates/gpui2/src/elements/uniform_list.rs | 81 +++++++++++++++---- crates/gpui2/src/view.rs | 2 +- 3 files changed, 82 insertions(+), 68 deletions(-) diff --git a/crates/command_palette2/src/command_palette.rs b/crates/command_palette2/src/command_palette.rs index 6816ecf3a2be696b2dc31882749ae63ce4972ad6..fda3dfa8b747c6296bada40f9b2fbfe173a893ab 100644 --- a/crates/command_palette2/src/command_palette.rs +++ b/crates/command_palette2/src/command_palette.rs @@ -147,6 +147,7 @@ impl PickerDelegate for CommandPaletteDelegate { type ListItem = Div>; fn match_count(&self) -> usize { + dbg!(self.matches.len()); self.matches.len() } @@ -163,44 +164,11 @@ impl PickerDelegate for CommandPaletteDelegate { query: String, cx: &mut ViewContext>, ) -> gpui::Task<()> { - let view_id = &self.previous_focus_handle; - let window = cx.window(); - cx.spawn(move |picker, mut cx| async move { - let mut actions = picker - .update(&mut cx, |this, _| this.delegate.commands.clone()) - .expect("todo: handle picker no longer being around"); - // _ = window - // .available_actions(view_id, &cx) - // .into_iter() - // .flatten() - // .filter_map(|(name, action, bindings)| { - // let filtered = cx.read(|cx| { - // if cx.has_global::() { - // let filter = cx.global::(); - // filter.filtered_namespaces.contains(action.namespace()) - // } else { - // false - // } - // }); - - // if filtered { - // None - // } else { - // Some(Command { - // name: humanize_action_name(name), - // action, - // keystrokes: bindings - // .iter() - // .map(|binding| binding.keystrokes()) - // .last() - // .map_or(Vec::new(), |keystrokes| keystrokes.to_vec()), - // }) - // } - // }) - // .collect::>(); + let mut commands = self.commands.clone(); + cx.spawn(move |picker, mut cx| async move { cx.read_global::(|hit_counts, _| { - actions.sort_by_key(|action| { + commands.sort_by_key(|action| { ( Reverse(hit_counts.0.get(&action.name).cloned()), action.name.clone(), @@ -209,7 +177,7 @@ impl PickerDelegate for CommandPaletteDelegate { }) .ok(); - let candidates = actions + let candidates = commands .iter() .enumerate() .map(|(ix, command)| StringMatchCandidate { @@ -240,15 +208,13 @@ impl PickerDelegate for CommandPaletteDelegate { ) .await }; - let mut intercept_result = None; - // todo!() for vim mode - // cx.read(|cx| { - // if cx.has_global::() { - // cx.global::()(&query, cx) - // } else { - // None - // } - // }); + + let mut intercept_result = cx + .try_read_global(|interceptor: &CommandPaletteInterceptor, cx| { + (interceptor)(&query, cx) + }) + .flatten(); + if *RELEASE_CHANNEL == ReleaseChannel::Dev { if parse_zed_link(&query).is_some() { intercept_result = Some(CommandInterceptResult { @@ -266,11 +232,11 @@ impl PickerDelegate for CommandPaletteDelegate { { if let Some(idx) = matches .iter() - .position(|m| actions[m.candidate_id].action.type_id() == action.type_id()) + .position(|m| commands[m.candidate_id].action.type_id() == action.type_id()) { matches.remove(idx); } - actions.push(Command { + commands.push(Command { name: string.clone(), action, keystrokes: vec![], @@ -278,7 +244,7 @@ impl PickerDelegate for CommandPaletteDelegate { matches.insert( 0, StringMatch { - candidate_id: actions.len() - 1, + candidate_id: commands.len() - 1, string, positions, score: 0.0, @@ -288,7 +254,8 @@ impl PickerDelegate for CommandPaletteDelegate { picker .update(&mut cx, |picker, _| { let delegate = &mut picker.delegate; - delegate.commands = actions; + dbg!(&matches); + delegate.commands = commands; delegate.matches = matches; if delegate.matches.is_empty() { delegate.selected_ix = 0; diff --git a/crates/gpui2/src/elements/uniform_list.rs b/crates/gpui2/src/elements/uniform_list.rs index e1160227637c8374fa47e922a0fabb509308ec1e..151696b8c95e39ba2f430c035f202159a5342ad4 100644 --- a/crates/gpui2/src/elements/uniform_list.rs +++ b/crates/gpui2/src/elements/uniform_list.rs @@ -1,6 +1,6 @@ use crate::{ - point, px, AnyElement, AvailableSpace, BorrowWindow, Bounds, Component, Element, ElementId, - ElementInteractivity, InteractiveElementState, LayoutId, Pixels, Point, Size, + point, px, size, AnyElement, AvailableSpace, BorrowWindow, Bounds, Component, Element, + ElementId, ElementInteractivity, InteractiveElementState, LayoutId, Pixels, Point, Size, StatefulInteractive, StatefulInteractivity, StatelessInteractive, StatelessInteractivity, StyleRefinement, Styled, ViewContext, }; @@ -86,8 +86,14 @@ impl Styled for UniformList { } } +#[derive(Default)] +pub struct UniformListState { + interactive: InteractiveElementState, + item_size: Size, +} + impl Element for UniformList { - type ElementState = InteractiveElementState; + type ElementState = UniformListState; fn id(&self) -> Option { Some(self.id.clone()) @@ -95,20 +101,49 @@ impl Element for UniformList { fn initialize( &mut self, - _: &mut V, + view_state: &mut V, element_state: Option, - _: &mut ViewContext, + cx: &mut ViewContext, ) -> Self::ElementState { - element_state.unwrap_or_default() + element_state.unwrap_or_else(|| { + let item_size = self.measure_first_item(view_state, None, cx); + UniformListState { + interactive: InteractiveElementState::default(), + item_size, + } + }) } fn layout( &mut self, _view_state: &mut V, - _element_state: &mut Self::ElementState, + element_state: &mut Self::ElementState, cx: &mut ViewContext, ) -> LayoutId { - cx.request_layout(&self.computed_style(), None) + let max_items = self.item_count; + let item_size = element_state.item_size; + let rem_size = cx.rem_size(); + cx.request_measured_layout( + self.computed_style(), + rem_size, + move |known_dimensions: Size>, available_space: Size| { + let desired_height = item_size.height * max_items; + let width = known_dimensions + .width + .unwrap_or(match available_space.width { + AvailableSpace::Definite(x) => x, + AvailableSpace::MinContent => item_size.width, + AvailableSpace::MaxContent => item_size.width, + }); + let height = match available_space.height { + AvailableSpace::Definite(x) => desired_height.min(x), + AvailableSpace::MinContent => desired_height, + AvailableSpace::MaxContent => desired_height, + }; + dbg!(known_dimensions, available_space, size(width, height)); + size(width, height) + }, + ) } fn paint( @@ -133,12 +168,15 @@ impl Element for UniformList { cx.with_z_index(style.z_index.unwrap_or(0), |cx| { let content_size; if self.item_count > 0 { - let item_height = self.measure_item_height(view_state, padded_bounds, cx); + let item_height = self + .measure_first_item(view_state, Some(padded_bounds.size.width), cx) + .height; + dbg!(item_height, padded_bounds); if let Some(scroll_handle) = self.scroll_handle.clone() { scroll_handle.0.lock().replace(ScrollHandleState { item_height, list_height: padded_bounds.size.height, - scroll_offset: element_state.track_scroll_offset(), + scroll_offset: element_state.interactive.track_scroll_offset(), }); } let visible_item_count = if item_height > px(0.) { @@ -146,7 +184,9 @@ impl Element for UniformList { } else { 0 }; + dbg!(visible_item_count); let scroll_offset = element_state + .interactive .scroll_offset() .map_or((0.0).into(), |offset| offset.y); let first_visible_element_ix = (-scroll_offset / item_height).floor() as usize; @@ -190,20 +230,25 @@ impl Element for UniformList { let overflow = point(style.overflow.x, Overflow::Scroll); cx.with_z_index(0, |cx| { - self.interactivity - .paint(bounds, content_size, overflow, element_state, cx); + self.interactivity.paint( + bounds, + content_size, + overflow, + &mut element_state.interactive, + cx, + ); }); }) } } impl UniformList { - fn measure_item_height( + fn measure_first_item( &self, view_state: &mut V, - list_bounds: Bounds, + list_width: Option, cx: &mut ViewContext, - ) -> Pixels { + ) -> Size { let mut items = (self.render_items)(view_state, 0..1, cx); debug_assert!(items.len() == 1); let mut item_to_measure = items.pop().unwrap(); @@ -212,11 +257,13 @@ impl UniformList { cx.compute_layout( layout_id, Size { - width: AvailableSpace::Definite(list_bounds.size.width), + width: list_width.map_or(AvailableSpace::MinContent, |width| { + AvailableSpace::Definite(width) + }), height: AvailableSpace::MinContent, }, ); - cx.layout_bounds(layout_id).size.height + cx.layout_bounds(layout_id).size } pub fn track_scroll(mut self, handle: UniformListScrollHandle) -> Self { diff --git a/crates/gpui2/src/view.rs b/crates/gpui2/src/view.rs index ffea7c451729351c0b22a6e655961523c7ed2a3f..00e1e55cd57d0fc96deb8d57be7f68f3c3b1f5bd 100644 --- a/crates/gpui2/src/view.rs +++ b/crates/gpui2/src/view.rs @@ -145,7 +145,7 @@ impl Eq for WeakView {} #[derive(Clone, Debug)] pub struct AnyView { model: AnyModel, - pub initialize: fn(&AnyView, &mut WindowContext) -> AnyBox, + initialize: fn(&AnyView, &mut WindowContext) -> AnyBox, layout: fn(&AnyView, &mut AnyBox, &mut WindowContext) -> LayoutId, paint: fn(&AnyView, &mut AnyBox, &mut WindowContext), }