From b09d2219d03be2bb8eec06ef5a07acf949c9881d Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Sat, 9 Dec 2023 12:00:44 +0100 Subject: [PATCH] Add basic landing page --- crates/search2/src/project_search.rs | 199 +++++++++++++++++---------- 1 file changed, 129 insertions(+), 70 deletions(-) diff --git a/crates/search2/src/project_search.rs b/crates/search2/src/project_search.rs index 18c101088bb20b88ad7a577ddcea4793b7b5366f..b1229b1b9fb3d5a0ddf0d95b8fd27f79d91218dd 100644 --- a/crates/search2/src/project_search.rs +++ b/crates/search2/src/project_search.rs @@ -14,9 +14,9 @@ use editor::{ }; use gpui::{ actions, div, white, Action, AnyElement, AnyView, AppContext, Context as _, Div, Element, - Entity, EntityId, EventEmitter, FocusableView, InteractiveElement, IntoElement, Model, - ModelContext, ParentElement, PromptLevel, Render, SharedString, Styled, Subscription, Task, - View, ViewContext, VisualContext, WeakModel, WeakView, WindowContext, + Entity, EntityId, EventEmitter, FocusableView, InteractiveElement, IntoElement, KeyContext, + Model, ModelContext, ParentElement, PromptLevel, Render, SharedString, Styled, Subscription, + Task, View, ViewContext, VisualContext, WeakModel, WeakView, WindowContext, }; use menu::Confirm; use project::{ @@ -39,7 +39,7 @@ use std::{ use theme::ActiveTheme; use ui::{ h_stack, v_stack, Button, Clickable, Color, Disableable, Icon, IconButton, IconElement, Label, - Selectable, + LabelCommon, LabelSize, Selectable, }; use util::{paths::PathMatcher, ResultExt as _}; use workspace::{ @@ -330,10 +330,30 @@ impl Render for ProjectSearchView { .size_full() .child(self.results_editor.clone()) } else { - div() + let has_no_results = self.model.read(cx).no_results.unwrap_or(false); + let middle_text = if has_no_results { + div() + .items_center() + .max_w_96() + .child(Label::new("No results for a given query")) + } else { + div() + .items_center() + .max_w_96() + .child(Label::new(self.landing_text_minor()).size(LabelSize::Small)) + }; + v_stack().flex_1().size_full().justify_center().child( + h_stack() + .size_full() + .justify_center() + .child(h_stack().flex_1()) + .child(middle_text) + .child(h_stack().flex_1()), + ) } } } + // impl Entity for ProjectSearchView { // type Event = ViewEvent; // } @@ -441,49 +461,6 @@ impl Render for ProjectSearchView { // } // }; -// let previous_query_keystrokes = -// cx.binding_for_action(&PreviousHistoryQuery {}) -// .map(|binding| { -// binding -// .keystrokes() -// .iter() -// .map(|k| k.to_string()) -// .collect::>() -// }); -// let next_query_keystrokes = -// cx.binding_for_action(&NextHistoryQuery {}).map(|binding| { -// binding -// .keystrokes() -// .iter() -// .map(|k| k.to_string()) -// .collect::>() -// }); -// let new_placeholder_text = match (previous_query_keystrokes, next_query_keystrokes) { -// (Some(previous_query_keystrokes), Some(next_query_keystrokes)) => { -// format!( -// "Search ({}/{} for previous/next query)", -// previous_query_keystrokes.join(" "), -// next_query_keystrokes.join(" ") -// ) -// } -// (None, Some(next_query_keystrokes)) => { -// format!( -// "Search ({} for next query)", -// next_query_keystrokes.join(" ") -// ) -// } -// (Some(previous_query_keystrokes), None) => { -// format!( -// "Search ({} for previous query)", -// previous_query_keystrokes.join(" ") -// ) -// } -// (None, None) => String::new(), -// }; -// self.query_editor.update(cx, |editor, cx| { -// editor.set_placeholder_text(new_placeholder_text, cx); -// }); - // MouseEventHandler::new::(0, cx, |_, _| { // Flex::column() // .with_child(Flex::column().contained().flex(1., true)) @@ -1355,6 +1332,12 @@ impl ProjectSearchView { }); } } + fn landing_text_minor(&self) -> SharedString { + match self.current_mode { + SearchMode::Text | SearchMode::Regex => "Include/exclude specific paths with the filter option. Matching exact word and/or casing is available too.".into(), + SearchMode::Semantic => ".Simply explain the code you are looking to find. ex. 'prompt user for permissions to index their project'".into() + } + } } impl Default for ProjectSearchBar { @@ -1680,6 +1663,47 @@ impl ProjectSearchBar { }); } } + fn new_placeholder_text(&self, cx: &mut ViewContext) -> Option { + let previous_query_keystrokes = cx + .bindings_for_action(&PreviousHistoryQuery {}) + .into_iter() + .next() + .map(|binding| { + binding + .keystrokes() + .iter() + .map(|k| k.to_string()) + .collect::>() + }); + let next_query_keystrokes = cx + .bindings_for_action(&NextHistoryQuery {}) + .into_iter() + .next() + .map(|binding| { + binding + .keystrokes() + .iter() + .map(|k| k.to_string()) + .collect::>() + }); + let new_placeholder_text = match (previous_query_keystrokes, next_query_keystrokes) { + (Some(previous_query_keystrokes), Some(next_query_keystrokes)) => Some(format!( + "Search ({}/{} for previous/next query)", + previous_query_keystrokes.join(" "), + next_query_keystrokes.join(" ") + )), + (None, Some(next_query_keystrokes)) => Some(format!( + "Search ({} for next query)", + next_query_keystrokes.join(" ") + )), + (Some(previous_query_keystrokes), None) => Some(format!( + "Search ({} for previous query)", + previous_query_keystrokes.join(" ") + )), + (None, None) => None, + }; + new_placeholder_text + } } impl Render for ProjectSearchBar { @@ -1689,7 +1713,17 @@ impl Render for ProjectSearchBar { let Some(search) = self.active_project_search.clone() else { return div(); }; + let mut key_context = KeyContext::default(); + key_context.add("ProjectSearchBar"); + if let Some(placeholder_text) = self.new_placeholder_text(cx) { + search.update(cx, |search, cx| { + search.query_editor.update(cx, |this, cx| { + this.set_placeholder_text(placeholder_text, cx) + }) + }); + } let search = search.read(cx); + let query_column = v_stack() .flex_1() .child( @@ -1714,6 +1748,10 @@ impl Render for ProjectSearchBar { .on_action(cx.listener(|this, action: &ActivateRegexMode, cx| { this.activate_search_mode(SearchMode::Regex, cx) })) + .on_action( + cx.listener(|this, action, cx| this.previous_history_query(action, cx)), + ) + .on_action(cx.listener(|this, action, cx| this.next_history_query(action, cx))) .child(IconElement::new(Icon::MagnifyingGlass)) .child(search.query_editor.clone()) .child( @@ -1740,34 +1778,54 @@ impl Render for ProjectSearchBar { .when(search.filters_enabled, |this| { this.child( h_stack() - .child(search.included_files_editor.clone()) - .child(search.excluded_files_editor.clone()), + .mt_2() + .flex_1() + .justify_between() + .child( + h_stack() + .flex_1() + .border_1() + .mr_2() + .child(search.included_files_editor.clone()), + ) + .child( + h_stack() + .flex_1() + .border_1() + .ml_2() + .child(search.excluded_files_editor.clone()), + ), ) }); - let mode_column = h_stack() - .child( - h_stack() - .child( - Button::new("project-search-text-button", "Text") - .selected(search.current_mode == SearchMode::Text) - .on_click(|_, cx| cx.dispatch_action(ActivateTextMode.boxed_clone())), - ) - .child( - Button::new("project-search-regex-button", "Regex") - .selected(search.current_mode == SearchMode::Regex) - .on_click(|_, cx| cx.dispatch_action(ActivateRegexMode.boxed_clone())), + let mode_column = v_stack().items_start().justify_start().child( + h_stack() + .child( + h_stack() + .child( + Button::new("project-search-text-button", "Text") + .selected(search.current_mode == SearchMode::Text) + .on_click(|_, cx| { + cx.dispatch_action(ActivateTextMode.boxed_clone()) + }), + ) + .child( + Button::new("project-search-regex-button", "Regex") + .selected(search.current_mode == SearchMode::Regex) + .on_click(|_, cx| { + cx.dispatch_action(ActivateRegexMode.boxed_clone()) + }), + ), + ) + .child( + IconButton::new("project-search-toggle-replace", Icon::Replace).on_click( + |_, cx| { + cx.dispatch_action(ToggleReplace.boxed_clone()); + }, ), - ) - .child( - IconButton::new("project-search-toggle-replace", Icon::Replace).on_click( - |_, cx| { - cx.dispatch_action(ToggleReplace.boxed_clone()); - }, ), - ); + ); let replace_column = if search.replace_enabled { h_stack() - .bg(white()) .p_1() .flex_1() .border_2() @@ -1811,6 +1869,7 @@ impl Render for ProjectSearchBar { .on_click(|_, cx| cx.dispatch_action(SelectNextMatch.boxed_clone())), ]); h_stack() + .key_context(key_context) .size_full() .p_1() .m_2()