diff --git a/crates/command_palette2/src/command_palette.rs b/crates/command_palette2/src/command_palette.rs index bf9f9fa94b9691405f4ff9f682e6abcf9c6b0b18..c7a6c9ee834b81685ca94a0227202a97daaeae8d 100644 --- a/crates/command_palette2/src/command_palette.rs +++ b/crates/command_palette2/src/command_palette.rs @@ -6,9 +6,12 @@ use gpui::{ WeakView, WindowContext, }; use picker::{Picker, PickerDelegate}; -use std::cmp::{self, Reverse}; +use std::{ + cmp::{self, Reverse}, + sync::Arc, +}; use theme::ActiveTheme; -use ui::{v_stack, Label, StyledExt}; +use ui::{v_stack, HighlightedLabel, StyledExt}; use util::{ channel::{parse_zed_link, ReleaseChannel, RELEASE_CHANNEL}, ResultExt, @@ -147,6 +150,10 @@ impl CommandPaletteDelegate { impl PickerDelegate for CommandPaletteDelegate { type ListItem = Div>; + fn placeholder_text(&self) -> Arc { + "Execute a command...".into() + } + fn match_count(&self) -> usize { self.matches.len() } @@ -296,11 +303,10 @@ impl PickerDelegate for CommandPaletteDelegate { cx: &mut ViewContext>, ) -> Self::ListItem { let colors = cx.theme().colors(); - let Some(command) = self - .matches - .get(ix) - .and_then(|m| self.commands.get(m.candidate_id)) - else { + let Some(r#match) = self.matches.get(ix) else { + return div(); + }; + let Some(command) = self.commands.get(r#match.candidate_id) else { return div(); }; @@ -312,7 +318,10 @@ impl PickerDelegate for CommandPaletteDelegate { .rounded_md() .when(selected, |this| this.bg(colors.ghost_element_selected)) .hover(|this| this.bg(colors.ghost_element_hover)) - .child(Label::new(command.name.clone())) + .child(HighlightedLabel::new( + command.name.clone(), + r#match.positions.clone(), + )) } // fn render_match( diff --git a/crates/picker2/src/picker2.rs b/crates/picker2/src/picker2.rs index ac1c5f89ea07e058d39ed07173437f3c59cf3c56..0a731b4a27027b59e43f4a8a39f654ad241839c3 100644 --- a/crates/picker2/src/picker2.rs +++ b/crates/picker2/src/picker2.rs @@ -4,8 +4,8 @@ use gpui::{ StatelessInteractive, Styled, Task, UniformListScrollHandle, View, ViewContext, VisualContext, WindowContext, }; -use std::cmp; -use ui::{prelude::*, v_stack, Divider}; +use std::{cmp, sync::Arc}; +use ui::{prelude::*, v_stack, Divider, Label, LabelColor}; pub struct Picker { pub delegate: D, @@ -21,7 +21,7 @@ pub trait PickerDelegate: Sized + 'static { fn selected_index(&self) -> usize; fn set_selected_index(&mut self, ix: usize, cx: &mut ViewContext>); - // fn placeholder_text(&self) -> Arc; + fn placeholder_text(&self) -> Arc; fn update_matches(&mut self, query: String, cx: &mut ViewContext>) -> Task<()>; fn confirm(&mut self, secondary: bool, cx: &mut ViewContext>); @@ -37,7 +37,11 @@ pub trait PickerDelegate: Sized + 'static { impl Picker { pub fn new(delegate: D, cx: &mut ViewContext) -> Self { - let editor = cx.build_view(|cx| Editor::single_line(cx)); + let editor = cx.build_view(|cx| { + let mut editor = Editor::single_line(cx); + editor.set_placeholder_text(delegate.placeholder_text(), cx); + editor + }); cx.subscribe(&editor, Self::on_input_editor_event).detach(); Self { delegate, @@ -159,23 +163,35 @@ impl Render for Picker { .child(div().px_1().py_0p5().child(self.editor.clone())), ) .child(Divider::horizontal()) - .child( - v_stack() - .p_1() - .grow() - .child( - uniform_list("candidates", self.delegate.match_count(), { - move |this: &mut Self, visible_range, cx| { - let selected_ix = this.delegate.selected_index(); - visible_range - .map(|ix| this.delegate.render_match(ix, ix == selected_ix, cx)) - .collect() - } - }) - .track_scroll(self.scroll_handle.clone()), - ) - .max_h_72() - .overflow_hidden(), - ) + .when(self.delegate.match_count() > 0, |el| { + el.child( + v_stack() + .p_1() + .grow() + .child( + uniform_list("candidates", self.delegate.match_count(), { + move |this: &mut Self, visible_range, cx| { + let selected_ix = this.delegate.selected_index(); + visible_range + .map(|ix| { + this.delegate.render_match(ix, ix == selected_ix, cx) + }) + .collect() + } + }) + .track_scroll(self.scroll_handle.clone()), + ) + .max_h_72() + .overflow_hidden(), + ) + }) + .when(self.delegate.match_count() == 0, |el| { + el.child( + v_stack() + .p_1() + .grow() + .child(Label::new("No matches").color(LabelColor::Muted)), + ) + }) } } diff --git a/crates/storybook2/src/stories/picker.rs b/crates/storybook2/src/stories/picker.rs index 82a010e6b30e820681b903232b74c35cad6b8584..067c190575acebad345479b88fe6cf164c19ef81 100644 --- a/crates/storybook2/src/stories/picker.rs +++ b/crates/storybook2/src/stories/picker.rs @@ -44,6 +44,10 @@ impl PickerDelegate for Delegate { self.candidates.len() } + fn placeholder_text(&self) -> Arc { + "Test".into() + } + fn render_match( &self, ix: usize,