Show placeholder text for pickers

This commit is contained in:
Antonio Scandurra 2022-11-04 10:18:29 +01:00
parent 08b84416d2
commit 0b231e58fd
19 changed files with 76 additions and 40 deletions

1
Cargo.lock generated
View file

@ -4012,6 +4012,7 @@ dependencies = [
"env_logger", "env_logger",
"gpui", "gpui",
"menu", "menu",
"parking_lot 0.11.2",
"serde_json", "serde_json",
"settings", "settings",
"theme", "theme",

View file

@ -170,8 +170,8 @@ impl ContactFinder {
let this = cx.weak_handle(); let this = cx.weak_handle();
Self { Self {
picker: cx.add_view(|cx| { picker: cx.add_view(|cx| {
Picker::new(this, cx) Picker::new("Search collaborator by username...", this, cx)
.with_theme(|cx| &cx.global::<Settings>().theme.contact_finder.picker) .with_theme(|theme| theme.contact_finder.picker.clone())
}), }),
potential_contacts: Arc::from([]), potential_contacts: Arc::from([]),
user_store, user_store,

View file

@ -175,7 +175,9 @@ impl ContactList {
) -> Self { ) -> Self {
let filter_editor = cx.add_view(|cx| { let filter_editor = cx.add_view(|cx| {
let mut editor = Editor::single_line( let mut editor = Editor::single_line(
Some(|theme| theme.contact_list.user_query_editor.clone()), Some(Arc::new(|theme| {
theme.contact_list.user_query_editor.clone()
})),
cx, cx,
); );
editor.set_placeholder_text("Filter contacts", cx); editor.set_placeholder_text("Filter contacts", cx);

View file

@ -70,7 +70,7 @@ impl CommandPalette {
}) })
.collect(); .collect();
let picker = cx.add_view(|cx| Picker::new(this, cx)); let picker = cx.add_view(|cx| Picker::new("Execute a command...", this, cx));
Self { Self {
picker, picker,
actions, actions,

View file

@ -437,8 +437,7 @@ pub struct EditorStyle {
type CompletionId = usize; type CompletionId = usize;
pub type GetFieldEditorTheme = fn(&theme::Theme) -> theme::FieldEditor; type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>; type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -523,7 +522,7 @@ pub struct Editor {
scroll_top_anchor: Anchor, scroll_top_anchor: Anchor,
autoscroll_request: Option<(Autoscroll, bool)>, autoscroll_request: Option<(Autoscroll, bool)>,
soft_wrap_mode_override: Option<settings::SoftWrap>, soft_wrap_mode_override: Option<settings::SoftWrap>,
get_field_editor_theme: Option<GetFieldEditorTheme>, get_field_editor_theme: Option<Arc<GetFieldEditorTheme>>,
override_text_style: Option<Box<OverrideTextStyle>>, override_text_style: Option<Box<OverrideTextStyle>>,
project: Option<ModelHandle<Project>>, project: Option<ModelHandle<Project>>,
focused: bool, focused: bool,
@ -1070,7 +1069,7 @@ enum GotoDefinitionKind {
impl Editor { impl Editor {
pub fn single_line( pub fn single_line(
field_editor_style: Option<GetFieldEditorTheme>, field_editor_style: Option<Arc<GetFieldEditorTheme>>,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) -> Self { ) -> Self {
let buffer = cx.add_model(|cx| Buffer::new(0, String::new(), cx)); let buffer = cx.add_model(|cx| Buffer::new(0, String::new(), cx));
@ -1080,7 +1079,7 @@ impl Editor {
pub fn auto_height( pub fn auto_height(
max_lines: usize, max_lines: usize,
field_editor_style: Option<GetFieldEditorTheme>, field_editor_style: Option<Arc<GetFieldEditorTheme>>,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) -> Self { ) -> Self {
let buffer = cx.add_model(|cx| Buffer::new(0, String::new(), cx)); let buffer = cx.add_model(|cx| Buffer::new(0, String::new(), cx));
@ -1116,7 +1115,7 @@ impl Editor {
self.mode, self.mode,
self.buffer.clone(), self.buffer.clone(),
self.project.clone(), self.project.clone(),
self.get_field_editor_theme, self.get_field_editor_theme.clone(),
cx, cx,
); );
self.display_map.update(cx, |display_map, cx| { self.display_map.update(cx, |display_map, cx| {
@ -1136,12 +1135,12 @@ impl Editor {
mode: EditorMode, mode: EditorMode,
buffer: ModelHandle<MultiBuffer>, buffer: ModelHandle<MultiBuffer>,
project: Option<ModelHandle<Project>>, project: Option<ModelHandle<Project>>,
get_field_editor_theme: Option<GetFieldEditorTheme>, get_field_editor_theme: Option<Arc<GetFieldEditorTheme>>,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) -> Self { ) -> Self {
let display_map = cx.add_model(|cx| { let display_map = cx.add_model(|cx| {
let settings = cx.global::<Settings>(); let settings = cx.global::<Settings>();
let style = build_style(&*settings, get_field_editor_theme, None, cx); let style = build_style(&*settings, get_field_editor_theme.as_deref(), None, cx);
DisplayMap::new( DisplayMap::new(
buffer.clone(), buffer.clone(),
style.text.font_id, style.text.font_id,
@ -1289,7 +1288,7 @@ impl Editor {
fn style(&self, cx: &AppContext) -> EditorStyle { fn style(&self, cx: &AppContext) -> EditorStyle {
build_style( build_style(
cx.global::<Settings>(), cx.global::<Settings>(),
self.get_field_editor_theme, self.get_field_editor_theme.as_deref(),
self.override_text_style.as_deref(), self.override_text_style.as_deref(),
cx, cx,
) )
@ -6846,7 +6845,7 @@ impl View for Editor {
fn build_style( fn build_style(
settings: &Settings, settings: &Settings,
get_field_editor_theme: Option<GetFieldEditorTheme>, get_field_editor_theme: Option<&GetFieldEditorTheme>,
override_text_style: Option<&OverrideTextStyle>, override_text_style: Option<&OverrideTextStyle>,
cx: &AppContext, cx: &AppContext,
) -> EditorStyle { ) -> EditorStyle {

View file

@ -1186,7 +1186,7 @@ impl EditorElement {
} }
// When the editor is empty and unfocused, then show the placeholder. // When the editor is empty and unfocused, then show the placeholder.
if snapshot.is_empty() && !snapshot.is_focused() { if snapshot.is_empty() {
let placeholder_style = self let placeholder_style = self
.style .style
.placeholder_text .placeholder_text

View file

@ -119,7 +119,7 @@ impl FileFinder {
cx.observe(&project, Self::project_updated).detach(); cx.observe(&project, Self::project_updated).detach();
Self { Self {
project, project,
picker: cx.add_view(|cx| Picker::new(handle, cx)), picker: cx.add_view(|cx| Picker::new("Search project files...", handle, cx)),
search_count: 0, search_count: 0,
latest_search_id: 0, latest_search_id: 0,
latest_search_did_cancel: false, latest_search_did_cancel: false,

View file

@ -1,3 +1,5 @@
use std::sync::Arc;
use editor::{display_map::ToDisplayPoint, Autoscroll, DisplayPoint, Editor}; use editor::{display_map::ToDisplayPoint, Autoscroll, DisplayPoint, Editor};
use gpui::{ use gpui::{
actions, elements::*, geometry::vector::Vector2F, AnyViewHandle, Axis, Entity, actions, elements::*, geometry::vector::Vector2F, AnyViewHandle, Axis, Entity,
@ -31,7 +33,10 @@ pub enum Event {
impl GoToLine { impl GoToLine {
pub fn new(active_editor: ViewHandle<Editor>, cx: &mut ViewContext<Self>) -> Self { pub fn new(active_editor: ViewHandle<Editor>, cx: &mut ViewContext<Self>) -> Self {
let line_editor = cx.add_view(|cx| { let line_editor = cx.add_view(|cx| {
Editor::single_line(Some(|theme| theme.picker.input_editor.clone()), cx) Editor::single_line(
Some(Arc::new(|theme| theme.picker.input_editor.clone())),
cx,
)
}); });
cx.subscribe(&line_editor, Self::on_line_editor_event) cx.subscribe(&line_editor, Self::on_line_editor_event)
.detach(); .detach();

View file

@ -67,7 +67,9 @@ impl OutlineView {
) -> Self { ) -> Self {
let handle = cx.weak_handle(); let handle = cx.weak_handle();
Self { Self {
picker: cx.add_view(|cx| Picker::new(handle, cx).with_max_size(800., 1200.)), picker: cx.add_view(|cx| {
Picker::new("Search buffer symbols...", handle, cx).with_max_size(800., 1200.)
}),
last_query: Default::default(), last_query: Default::default(),
matches: Default::default(), matches: Default::default(),
selected_match_index: 0, selected_match_index: 0,

View file

@ -16,6 +16,8 @@ util = { path = "../util" }
theme = { path = "../theme" } theme = { path = "../theme" }
workspace = { path = "../workspace" } workspace = { path = "../workspace" }
parking_lot = "0.11.1"
[dev-dependencies] [dev-dependencies]
gpui = { path = "../gpui", features = ["test-support"] } gpui = { path = "../gpui", features = ["test-support"] }
serde_json = { version = "1.0", features = ["preserve_order"] } serde_json = { version = "1.0", features = ["preserve_order"] }

View file

@ -8,15 +8,15 @@ use gpui::{
RenderContext, Task, View, ViewContext, ViewHandle, WeakViewHandle, RenderContext, Task, View, ViewContext, ViewHandle, WeakViewHandle,
}; };
use menu::{Cancel, Confirm, SelectFirst, SelectIndex, SelectLast, SelectNext, SelectPrev}; use menu::{Cancel, Confirm, SelectFirst, SelectIndex, SelectLast, SelectNext, SelectPrev};
use settings::Settings; use parking_lot::Mutex;
use std::cmp; use std::{cmp, sync::Arc};
pub struct Picker<D: PickerDelegate> { pub struct Picker<D: PickerDelegate> {
delegate: WeakViewHandle<D>, delegate: WeakViewHandle<D>,
query_editor: ViewHandle<Editor>, query_editor: ViewHandle<Editor>,
list_state: UniformListState, list_state: UniformListState,
max_size: Vector2F, max_size: Vector2F,
theme: Box<dyn FnMut(&AppContext) -> &theme::Picker>, theme: Arc<Mutex<Box<dyn Fn(&theme::Theme) -> theme::Picker>>>,
confirmed: bool, confirmed: bool,
} }
@ -49,7 +49,7 @@ impl<D: PickerDelegate> View for Picker<D> {
} }
fn render(&mut self, cx: &mut RenderContext<Self>) -> gpui::ElementBox { fn render(&mut self, cx: &mut RenderContext<Self>) -> gpui::ElementBox {
let theme = (self.theme)(cx); let theme = (self.theme.lock())(&cx.global::<settings::Settings>().theme);
let query = self.query(cx); let query = self.query(cx);
let delegate = self.delegate.clone(); let delegate = self.delegate.clone();
let match_count = if let Some(delegate) = delegate.upgrade(cx.app) { let match_count = if let Some(delegate) = delegate.upgrade(cx.app) {
@ -148,9 +148,26 @@ impl<D: PickerDelegate> Picker<D> {
cx.add_action(Self::cancel); cx.add_action(Self::cancel);
} }
pub fn new(delegate: WeakViewHandle<D>, cx: &mut ViewContext<Self>) -> Self { pub fn new<P>(placeholder: P, delegate: WeakViewHandle<D>, cx: &mut ViewContext<Self>) -> Self
let query_editor = cx.add_view(|cx| { where
Editor::single_line(Some(|theme| theme.picker.input_editor.clone()), cx) P: Into<Arc<str>>,
{
let theme = Arc::new(Mutex::new(
Box::new(|theme: &theme::Theme| theme.picker.clone())
as Box<dyn Fn(&theme::Theme) -> theme::Picker>,
));
let query_editor = cx.add_view({
let picker_theme = theme.clone();
|cx| {
let mut editor = Editor::single_line(
Some(Arc::new(move |theme| {
(picker_theme.lock())(theme).input_editor.clone()
})),
cx,
);
editor.set_placeholder_text(placeholder, cx);
editor
}
}); });
cx.subscribe(&query_editor, Self::on_query_editor_event) cx.subscribe(&query_editor, Self::on_query_editor_event)
.detach(); .detach();
@ -159,7 +176,7 @@ impl<D: PickerDelegate> Picker<D> {
list_state: Default::default(), list_state: Default::default(),
delegate, delegate,
max_size: vec2f(540., 420.), max_size: vec2f(540., 420.),
theme: Box::new(|cx| &cx.global::<Settings>().theme.picker), theme,
confirmed: false, confirmed: false,
}; };
cx.defer(|this, cx| { cx.defer(|this, cx| {
@ -176,11 +193,11 @@ impl<D: PickerDelegate> Picker<D> {
self self
} }
pub fn with_theme<F>(mut self, theme: F) -> Self pub fn with_theme<F>(self, theme: F) -> Self
where where
F: 'static + FnMut(&AppContext) -> &theme::Picker, F: 'static + Fn(&theme::Theme) -> theme::Picker,
{ {
self.theme = Box::new(theme); *self.theme.lock() = Box::new(theme);
self self
} }

View file

@ -23,6 +23,7 @@ use std::{
ffi::OsStr, ffi::OsStr,
ops::Range, ops::Range,
path::{Path, PathBuf}, path::{Path, PathBuf},
sync::Arc,
}; };
use unicase::UniCase; use unicase::UniCase;
use workspace::Workspace; use workspace::Workspace;
@ -175,11 +176,11 @@ impl ProjectPanel {
let filename_editor = cx.add_view(|cx| { let filename_editor = cx.add_view(|cx| {
Editor::single_line( Editor::single_line(
Some(|theme| { Some(Arc::new(|theme| {
let mut style = theme.project_panel.filename_editor.clone(); let mut style = theme.project_panel.filename_editor.clone();
style.container.background_color.take(); style.container.background_color.take();
style style
}), })),
cx, cx,
) )
}); });

View file

@ -63,7 +63,7 @@ impl ProjectSymbolsView {
let handle = cx.weak_handle(); let handle = cx.weak_handle();
Self { Self {
project, project,
picker: cx.add_view(|cx| Picker::new(handle, cx)), picker: cx.add_view(|cx| Picker::new("Search project symbols...", handle, cx)),
selected_match_index: 0, selected_match_index: 0,
symbols: Default::default(), symbols: Default::default(),
visible_match_candidates: Default::default(), visible_match_candidates: Default::default(),

View file

@ -12,7 +12,7 @@ use gpui::{
use project::search::SearchQuery; use project::search::SearchQuery;
use serde::Deserialize; use serde::Deserialize;
use settings::Settings; use settings::Settings;
use std::any::Any; use std::{any::Any, sync::Arc};
use workspace::{ use workspace::{
searchable::{Direction, SearchEvent, SearchableItemHandle, WeakSearchableItemHandle}, searchable::{Direction, SearchEvent, SearchableItemHandle, WeakSearchableItemHandle},
ItemHandle, Pane, ToolbarItemLocation, ToolbarItemView, ItemHandle, Pane, ToolbarItemLocation, ToolbarItemView,
@ -232,7 +232,11 @@ impl ToolbarItemView for BufferSearchBar {
impl BufferSearchBar { impl BufferSearchBar {
pub fn new(cx: &mut ViewContext<Self>) -> Self { pub fn new(cx: &mut ViewContext<Self>) -> Self {
let query_editor = cx.add_view(|cx| { let query_editor = cx.add_view(|cx| {
Editor::auto_height(2, Some(|theme| theme.search.editor.input.clone()), cx) Editor::auto_height(
2,
Some(Arc::new(|theme| theme.search.editor.input.clone())),
cx,
)
}); });
cx.subscribe(&query_editor, Self::on_query_editor_event) cx.subscribe(&query_editor, Self::on_query_editor_event)
.detach(); .detach();

View file

@ -20,6 +20,7 @@ use std::{
any::{Any, TypeId}, any::{Any, TypeId},
ops::Range, ops::Range,
path::PathBuf, path::PathBuf,
sync::Arc,
}; };
use util::ResultExt as _; use util::ResultExt as _;
use workspace::{ use workspace::{
@ -378,8 +379,10 @@ impl ProjectSearchView {
.detach(); .detach();
let query_editor = cx.add_view(|cx| { let query_editor = cx.add_view(|cx| {
let mut editor = let mut editor = Editor::single_line(
Editor::single_line(Some(|theme| theme.search.editor.input.clone()), cx); Some(Arc::new(|theme| theme.search.editor.input.clone())),
cx,
);
editor.set_text(query_text, cx); editor.set_text(query_text, cx);
editor editor
}); });

View file

@ -423,7 +423,7 @@ pub struct ChannelName {
pub name: TextStyle, pub name: TextStyle,
} }
#[derive(Deserialize, Default)] #[derive(Clone, Deserialize, Default)]
pub struct Picker { pub struct Picker {
#[serde(flatten)] #[serde(flatten)]
pub container: ContainerStyle, pub container: ContainerStyle,

View file

@ -38,7 +38,7 @@ pub enum Event {
impl ThemeSelector { impl ThemeSelector {
fn new(registry: Arc<ThemeRegistry>, cx: &mut ViewContext<Self>) -> Self { fn new(registry: Arc<ThemeRegistry>, cx: &mut ViewContext<Self>) -> Self {
let handle = cx.weak_handle(); let handle = cx.weak_handle();
let picker = cx.add_view(|cx| Picker::new(handle, cx)); let picker = cx.add_view(|cx| Picker::new("Select Theme...", handle, cx));
let settings = cx.global::<Settings>(); let settings = cx.global::<Settings>();
let original_theme = settings.theme.clone(); let original_theme = settings.theme.clone();

View file

@ -19,7 +19,7 @@ export default function contactFinder(colorScheme: ColorScheme) {
background: background(layer, "on"), background: background(layer, "on"),
cornerRadius: 6, cornerRadius: 6,
text: text(layer, "mono",), text: text(layer, "mono",),
placeholderText: text(layer, "mono", "variant", { size: "sm" }), placeholderText: text(layer, "mono", "on", "disabled", { size: "xs" }),
selection: colorScheme.players[0], selection: colorScheme.players[0],
border: border(layer), border: border(layer),
padding: { padding: {

View file

@ -53,7 +53,7 @@ export default function contactsPanel(colorScheme: ColorScheme) {
background: background(layer, "on"), background: background(layer, "on"),
cornerRadius: 6, cornerRadius: 6,
text: text(layer, "mono", "on"), text: text(layer, "mono", "on"),
placeholderText: text(layer, "mono", "on", "disabled", { size: "sm" }), placeholderText: text(layer, "mono", "on", "disabled", { size: "xs" }),
selection: colorScheme.players[0], selection: colorScheme.players[0],
border: border(layer, "on"), border: border(layer, "on"),
padding: { padding: {