Redine command palette style

Co-Authored-By: Marshall Bowers <1486634+maxdeviant@users.noreply.github.com>
Co-Authored-By: Conrad Irwin <conrad.irwin@gmail.com>
This commit is contained in:
Nate Butler 2023-11-13 13:13:40 -05:00
parent 031d841305
commit f6c54b8043
2 changed files with 52 additions and 30 deletions

View file

@ -2,13 +2,13 @@ use collections::{CommandPaletteFilter, HashMap};
use fuzzy::{StringMatch, StringMatchCandidate}; use fuzzy::{StringMatch, StringMatchCandidate};
use gpui::{ use gpui::{
actions, div, Action, AppContext, Component, Div, EventEmitter, FocusHandle, Keystroke, actions, div, Action, AppContext, Component, Div, EventEmitter, FocusHandle, Keystroke,
ParentElement, Render, StatelessInteractive, Styled, View, ViewContext, VisualContext, ParentElement, Render, SharedString, StatelessInteractive, Styled, View, ViewContext,
WeakView, WindowContext, VisualContext, WeakView, WindowContext,
}; };
use picker::{Picker, PickerDelegate}; use picker::{Picker, PickerDelegate};
use std::cmp::{self, Reverse}; use std::cmp::{self, Reverse};
use theme::ActiveTheme; use theme::ActiveTheme;
use ui::{v_stack, Label, StyledExt}; use ui::{v_stack, HighlightedLabel, StyledExt};
use util::{ use util::{
channel::{parse_zed_link, ReleaseChannel, RELEASE_CHANNEL}, channel::{parse_zed_link, ReleaseChannel, RELEASE_CHANNEL},
ResultExt, ResultExt,
@ -147,6 +147,10 @@ impl CommandPaletteDelegate {
impl PickerDelegate for CommandPaletteDelegate { impl PickerDelegate for CommandPaletteDelegate {
type ListItem = Div<Picker<Self>>; type ListItem = Div<Picker<Self>>;
fn placeholder_text(&self) -> Arc<str> {
"Execute a command...".into()
}
fn match_count(&self) -> usize { fn match_count(&self) -> usize {
self.matches.len() self.matches.len()
} }
@ -296,11 +300,10 @@ impl PickerDelegate for CommandPaletteDelegate {
cx: &mut ViewContext<Picker<Self>>, cx: &mut ViewContext<Picker<Self>>,
) -> Self::ListItem { ) -> Self::ListItem {
let colors = cx.theme().colors(); let colors = cx.theme().colors();
let Some(command) = self let Some(r#match) = self.matches.get(ix) else {
.matches return div();
.get(ix) };
.and_then(|m| self.commands.get(m.candidate_id)) let Some(command) = self.commands.get(r#match.candidate_id) else {
else {
return div(); return div();
}; };
@ -312,7 +315,10 @@ impl PickerDelegate for CommandPaletteDelegate {
.rounded_md() .rounded_md()
.when(selected, |this| this.bg(colors.ghost_element_selected)) .when(selected, |this| this.bg(colors.ghost_element_selected))
.hover(|this| this.bg(colors.ghost_element_hover)) .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( // fn render_match(

View file

@ -5,7 +5,7 @@ use gpui::{
WindowContext, WindowContext,
}; };
use std::cmp; use std::cmp;
use ui::{prelude::*, v_stack, Divider}; use ui::{prelude::*, v_stack, Divider, Label, LabelColor};
pub struct Picker<D: PickerDelegate> { pub struct Picker<D: PickerDelegate> {
pub delegate: D, pub delegate: D,
@ -21,7 +21,7 @@ pub trait PickerDelegate: Sized + 'static {
fn selected_index(&self) -> usize; fn selected_index(&self) -> usize;
fn set_selected_index(&mut self, ix: usize, cx: &mut ViewContext<Picker<Self>>); fn set_selected_index(&mut self, ix: usize, cx: &mut ViewContext<Picker<Self>>);
// fn placeholder_text(&self) -> Arc<str>; fn placeholder_text(&self) -> Arc<str>;
fn update_matches(&mut self, query: String, cx: &mut ViewContext<Picker<Self>>) -> Task<()>; fn update_matches(&mut self, query: String, cx: &mut ViewContext<Picker<Self>>) -> Task<()>;
fn confirm(&mut self, secondary: bool, cx: &mut ViewContext<Picker<Self>>); fn confirm(&mut self, secondary: bool, cx: &mut ViewContext<Picker<Self>>);
@ -37,7 +37,11 @@ pub trait PickerDelegate: Sized + 'static {
impl<D: PickerDelegate> Picker<D> { impl<D: PickerDelegate> Picker<D> {
pub fn new(delegate: D, cx: &mut ViewContext<Self>) -> Self { pub fn new(delegate: D, cx: &mut ViewContext<Self>) -> 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(); cx.subscribe(&editor, Self::on_input_editor_event).detach();
Self { Self {
delegate, delegate,
@ -159,23 +163,35 @@ impl<D: PickerDelegate> Render for Picker<D> {
.child(div().px_1().py_0p5().child(self.editor.clone())), .child(div().px_1().py_0p5().child(self.editor.clone())),
) )
.child(Divider::horizontal()) .child(Divider::horizontal())
.child( .when(self.delegate.match_count() > 0, |el| {
v_stack() el.child(
.p_1() v_stack()
.grow() .p_1()
.child( .grow()
uniform_list("candidates", self.delegate.match_count(), { .child(
move |this: &mut Self, visible_range, cx| { uniform_list("candidates", self.delegate.match_count(), {
let selected_ix = this.delegate.selected_index(); move |this: &mut Self, visible_range, cx| {
visible_range let selected_ix = this.delegate.selected_index();
.map(|ix| this.delegate.render_match(ix, ix == selected_ix, cx)) visible_range
.collect() .map(|ix| {
} this.delegate.render_match(ix, ix == selected_ix, cx)
}) })
.track_scroll(self.scroll_handle.clone()), .collect()
) }
.max_h_72() })
.overflow_hidden(), .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)),
)
})
} }
} }