Avoid showing "No matches" when query is empty if there are no matches

Antonio Scandurra created

Change summary

crates/go_to_line/src/go_to_line.rs   |  4 +-
crates/picker/src/picker.rs           | 48 ++++++++++++++++++----------
crates/theme/src/theme.rs             |  4 +
styles/src/styleTree/contactFinder.ts | 49 +++++++++++++++-------------
styles/src/styleTree/picker.ts        | 47 +++++++++++++++++----------
5 files changed, 93 insertions(+), 59 deletions(-)

Detailed changes

crates/go_to_line/src/go_to_line.rs 🔗

@@ -170,8 +170,8 @@ impl View for GoToLine {
                             .boxed(),
                     )
                     .with_child(
-                        Container::new(Label::new(label, theme.empty.label.clone()).boxed())
-                            .with_style(theme.empty.container)
+                        Container::new(Label::new(label, theme.no_matches.label.clone()).boxed())
+                            .with_style(theme.no_matches.container)
                             .boxed(),
                     )
                     .boxed(),

crates/picker/src/picker.rs 🔗

@@ -1,14 +1,11 @@
 use editor::Editor;
 use gpui::{
-    elements::{
-        ChildView, Flex, Label, MouseEventHandler, ParentElement, ScrollTarget, UniformList,
-        UniformListState,
-    },
+    elements::*,
     geometry::vector::{vec2f, Vector2F},
     keymap,
     platform::CursorStyle,
-    AnyViewHandle, AppContext, Axis, Element, ElementBox, Entity, MouseButton, MouseState,
-    MutableAppContext, RenderContext, Task, View, ViewContext, ViewHandle, WeakViewHandle,
+    AnyViewHandle, AppContext, Axis, Entity, MouseButton, MouseState, MutableAppContext,
+    RenderContext, Task, View, ViewContext, ViewHandle, WeakViewHandle,
 };
 use menu::{Cancel, Confirm, SelectFirst, SelectIndex, SelectLast, SelectNext, SelectPrev};
 use settings::Settings;
@@ -53,7 +50,7 @@ impl<D: PickerDelegate> View for Picker<D> {
 
     fn render(&mut self, cx: &mut RenderContext<Self>) -> gpui::ElementBox {
         let theme = (self.theme)(cx);
-        let container_style = theme.container;
+        let query = self.query(cx);
         let delegate = self.delegate.clone();
         let match_count = if let Some(delegate) = delegate.upgrade(cx.app) {
             delegate.read(cx).match_count()
@@ -61,19 +58,36 @@ impl<D: PickerDelegate> View for Picker<D> {
             0
         };
 
+        let container_style;
+        let editor_style;
+        if query.is_empty() && match_count == 0 {
+            container_style = theme.empty_container;
+            editor_style = theme.empty_input_editor.container;
+        } else {
+            container_style = theme.container;
+            editor_style = theme.input_editor.container;
+        };
+
         Flex::new(Axis::Vertical)
             .with_child(
                 ChildView::new(&self.query_editor, cx)
                     .contained()
-                    .with_style(theme.input_editor.container)
+                    .with_style(editor_style)
                     .boxed(),
             )
-            .with_child(
-                if match_count == 0 {
-                    Label::new("No matches".into(), theme.empty.label.clone())
-                        .contained()
-                        .with_style(theme.empty.container)
+            .with_children(if match_count == 0 {
+                if query.is_empty() {
+                    None
                 } else {
+                    Some(
+                        Label::new("No matches".into(), theme.no_matches.label.clone())
+                            .contained()
+                            .with_style(theme.no_matches.container)
+                            .boxed(),
+                    )
+                }
+            } else {
+                Some(
                     UniformList::new(
                         self.list_state.clone(),
                         match_count,
@@ -98,10 +112,10 @@ impl<D: PickerDelegate> View for Picker<D> {
                     )
                     .contained()
                     .with_margin_top(6.0)
-                }
-                .flex(1., false)
-                .boxed(),
-            )
+                    .flex(1., false)
+                    .boxed(),
+                )
+            })
             .contained()
             .with_style(container_style)
             .constrained()

crates/theme/src/theme.rs 🔗

@@ -427,8 +427,10 @@ pub struct ChannelName {
 pub struct Picker {
     #[serde(flatten)]
     pub container: ContainerStyle,
-    pub empty: ContainedLabel,
+    pub empty_container: ContainerStyle,
     pub input_editor: FieldEditor,
+    pub empty_input_editor: FieldEditor,
+    pub no_matches: ContainedLabel,
     pub item: Interactive<ContainedLabel>,
 }
 

styles/src/styleTree/contactFinder.ts 🔗

@@ -3,7 +3,7 @@ import { ColorScheme } from "../themes/common/colorScheme";
 import { background, border, foreground, text } from "./components";
 
 export default function contactFinder(colorScheme: ColorScheme) {
-  let layer = colorScheme.highest;
+  let layer = colorScheme.middle;
 
   const sideMargin = 6;
   const contactButton = {
@@ -14,31 +14,36 @@ export default function contactFinder(colorScheme: ColorScheme) {
     cornerRadius: 8,
   };
 
+  const pickerStyle = picker(colorScheme);
+  const pickerInput = {
+    background: background(layer, "on"),
+    cornerRadius: 6,
+    text: text(layer, "mono",),
+    placeholderText: text(layer, "mono", "variant", { size: "sm" }),
+    selection: colorScheme.players[0],
+    border: border(layer),
+    padding: {
+      bottom: 4,
+      left: 8,
+      right: 8,
+      top: 4,
+    },
+    margin: {
+      left: sideMargin,
+      right: sideMargin,
+    }
+  };
+
   return {
     picker: {
+      emptyContainer: {},
       item: {
-        ...picker(colorScheme).item,
-        margin: { left: sideMargin, right: sideMargin }
+        ...pickerStyle.item,
+        margin: { left: sideMargin, right: sideMargin },
       },
-      empty: picker(colorScheme).empty,
-      inputEditor: {
-        background: background(layer, "on"),
-        cornerRadius: 6,
-        text: text(layer, "mono",),
-        placeholderText: text(layer, "mono", "variant", { size: "sm" }),
-        selection: colorScheme.players[0],
-        border: border(layer),
-        padding: {
-          bottom: 4,
-          left: 8,
-          right: 8,
-          top: 4,
-        },
-        margin: {
-          left: sideMargin,
-          right: sideMargin,
-        }
-      }
+      noMatches: pickerStyle.noMatches,
+      inputEditor: pickerInput,
+      emptyInputEditor: pickerInput
     },
     rowHeight: 28,
     contactAvatar: {

styles/src/styleTree/picker.ts 🔗

@@ -3,13 +3,39 @@ import { background, border, text } from "./components";
 
 export default function picker(colorScheme: ColorScheme) {
   let layer = colorScheme.lowest;
-  return {
+  const container = {
     background: background(layer),
     border: border(layer),
     shadow: colorScheme.modalShadow,
     cornerRadius: 12,
     padding: {
       bottom: 4,
+    }
+  };
+  const inputEditor = {
+    placeholderText: text(layer, "sans", "on", "disabled"),
+    selection: colorScheme.players[0],
+    text: text(layer, "mono", "on"),
+    border: border(layer, { bottom: true }),
+    padding: {
+      bottom: 8,
+      left: 16,
+      right: 16,
+      top: 8,
+    },
+    margin: {
+      bottom: 4,
+    },
+  };
+  const emptyInputEditor = { ...inputEditor };
+  delete emptyInputEditor.border;
+  delete emptyInputEditor.margin;
+
+  return {
+    ...container,
+    emptyContainer: {
+      ...container,
+      padding: {}
     },
     item: {
       padding: {
@@ -37,7 +63,9 @@ export default function picker(colorScheme: ColorScheme) {
         background: background(layer, "hovered"),
       },
     },
-    empty: {
+    inputEditor,
+    emptyInputEditor,
+    noMatches: {
       text: text(layer, "sans", "variant"),
       padding: {
         bottom: 8,
@@ -46,20 +74,5 @@ export default function picker(colorScheme: ColorScheme) {
         top: 8,
       },
     },
-    inputEditor: {
-      placeholderText: text(layer, "sans", "on", "disabled"),
-      selection: colorScheme.players[0],
-      text: text(layer, "mono", "on"),
-      border: border(layer, { bottom: true }),
-      padding: {
-        bottom: 8,
-        left: 16,
-        right: 16,
-        top: 8,
-      },
-      margin: {
-        bottom: 4,
-      },
-    },
   };
 }