From f6c54b804397f2c01625c7ffbdf729042bc23412 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Mon, 13 Nov 2023 13:13:40 -0500 Subject: [PATCH] Redine command palette style Co-Authored-By: Marshall Bowers <1486634+maxdeviant@users.noreply.github.com> Co-Authored-By: Conrad Irwin --- .../command_palette2/src/command_palette.rs | 24 +++++--- crates/picker2/src/picker2.rs | 58 ++++++++++++------- 2 files changed, 52 insertions(+), 30 deletions(-) diff --git a/crates/command_palette2/src/command_palette.rs b/crates/command_palette2/src/command_palette.rs index bf9f9fa94b9691405f4ff9f682e6abcf9c6b0b18..508707f2648b6aa4c1145a6b761f3aa31a6f1dd8 100644 --- a/crates/command_palette2/src/command_palette.rs +++ b/crates/command_palette2/src/command_palette.rs @@ -2,13 +2,13 @@ use collections::{CommandPaletteFilter, HashMap}; use fuzzy::{StringMatch, StringMatchCandidate}; use gpui::{ actions, div, Action, AppContext, Component, Div, EventEmitter, FocusHandle, Keystroke, - ParentElement, Render, StatelessInteractive, Styled, View, ViewContext, VisualContext, - WeakView, WindowContext, + ParentElement, Render, SharedString, StatelessInteractive, Styled, View, ViewContext, + VisualContext, WeakView, WindowContext, }; use picker::{Picker, PickerDelegate}; use std::cmp::{self, Reverse}; 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 +147,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 +300,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 +315,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..1c42e2ed3f13dfe5f5cf81fcb1097fbfbd044e88 100644 --- a/crates/picker2/src/picker2.rs +++ b/crates/picker2/src/picker2.rs @@ -5,7 +5,7 @@ use gpui::{ WindowContext, }; use std::cmp; -use ui::{prelude::*, v_stack, Divider}; +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)), + ) + }) } }