diff --git a/crates/search2/src/buffer_search.rs b/crates/search2/src/buffer_search.rs index ccacff12aee080af441b9af0846672ed84eb2135..4e8584b80441b716e7335b6f0e2d6a1f8889115d 100644 --- a/crates/search2/src/buffer_search.rs +++ b/crates/search2/src/buffer_search.rs @@ -11,8 +11,8 @@ use editor::Editor; use futures::channel::oneshot; use gpui::{ action, actions, div, red, Action, AppContext, Component, Div, EventEmitter, - ParentComponent as _, Render, Styled, Subscription, Task, View, ViewContext, - VisualContext as _, WindowContext, + InteractiveComponent, ParentComponent as _, Render, Styled, Subscription, Task, View, + ViewContext, VisualContext as _, WindowContext, }; use project::search::SearchQuery; use std::{any::Any, sync::Arc}; @@ -38,7 +38,6 @@ pub enum Event { } pub fn init(cx: &mut AppContext) { - dbg!("Registered"); cx.observe_new_views(|workspace: &mut Workspace, _| BufferSearchBar::register(workspace)) .detach(); } @@ -78,45 +77,51 @@ impl Render for BufferSearchBar { .map(|active_searchable_item| active_searchable_item.supported_options()) .unwrap_or_default(); - // 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(), - // }; - let new_placeholder_text = Arc::from("Search for.."); + 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)) => { + 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(), + }; + let new_placeholder_text = Arc::from(new_placeholder_text); self.query_editor.update(cx, |editor, cx| { editor.set_placeholder_text(new_placeholder_text, cx); }); @@ -159,9 +164,9 @@ impl Render for BufferSearchBar { Some(ui::Label::new(message)) }); - let nav_button_for_direction = |label, direction, cx: &mut ViewContext| { + let nav_button_for_direction = |icon, direction, cx: &mut ViewContext| { render_nav_button( - label, + icon, direction, self.active_match_index.is_some(), move |this, cx| match direction { @@ -172,12 +177,32 @@ impl Render for BufferSearchBar { ) }; let should_show_replace_input = self.replace_enabled && supported_options.replacement; - let replace_all = should_show_replace_input.then(|| { - super::replace_action::(ReplaceAll, "Replace all", ui::Icon::ReplaceAll) - }); + let replace_all = should_show_replace_input + .then(|| super::render_replace_button::(ReplaceAll, ui::Icon::ReplaceAll)); let replace_next = should_show_replace_input - .then(|| super::replace_action::(ReplaceNext, "Replace next", ui::Icon::Replace)); + .then(|| super::render_replace_button::(ReplaceNext, ui::Icon::Replace)); + let in_replace = self.replacement_editor.focus_handle(cx).is_focused(cx); + h_stack() + .key_context("BufferSearchBar") + .when(in_replace, |this| { + this.key_context("in_replace") + .on_action(Self::replace_next) + .on_action(Self::replace_all) + }) + .on_action(Self::previous_history_query) + .on_action(Self::next_history_query) + .when(supported_options.case, |this| { + this.on_action(Self::toggle_case_sensitive) + }) + .when(supported_options.word, |this| { + this.on_action(Self::toggle_whole_word) + }) + .when(supported_options.replacement, |this| { + this.on_action(Self::toggle_replace) + }) + .on_action(Self::select_next_match) + .on_action(Self::select_prev_match) .w_full() .p_1() .child( @@ -226,9 +251,18 @@ impl Render for BufferSearchBar { h_stack() .gap_0p5() .flex_none() + .child(self.render_action_button(cx)) .children(match_count) - .child(nav_button_for_direction("<", Direction::Prev, cx)) - .child(nav_button_for_direction(">", Direction::Next, cx)), + .child(nav_button_for_direction( + ui::Icon::ChevronLeft, + Direction::Prev, + cx, + )) + .child(nav_button_for_direction( + ui::Icon::ChevronRight, + Direction::Next, + cx, + )), ) // let query_column = Flex::row() @@ -343,7 +377,7 @@ impl ToolbarItemView for BufferSearchBar { cx.notify(); self.active_searchable_item_subscription.take(); self.active_searchable_item.take(); - dbg!("Take?"); + self.pending_search.take(); if let Some(searchable_item_handle) = @@ -382,7 +416,8 @@ impl BufferSearchBar { workspace.register_action(|workspace, a: &Deploy, cx| { workspace.active_pane().update(cx, |this, cx| { this.toolbar().update(cx, |this, cx| { - if this.item_of_type::().is_some() { + if let Some(search_bar) = this.item_of_type::() { + search_bar.update(cx, |this, cx| this.dismiss(&Dismiss, cx)); return; } let view = cx.build_view(|cx| BufferSearchBar::new(cx)); @@ -392,46 +427,8 @@ impl BufferSearchBar { }) }); }); - fn register_action( - workspace: &mut Workspace, - update: fn(&mut BufferSearchBar, &mut ViewContext<'_, BufferSearchBar>), - ) { - workspace.register_action(move |workspace, _: &A, cx| { - workspace.active_pane().update(cx, move |this, cx| { - this.toolbar().update(cx, move |toolbar, cx| { - let Some(search_bar) = toolbar.item_of_type::() else { - return; - }; - search_bar.update(cx, |this, cx| update(this, cx)) - }) - }); - }); - } - register_action::(workspace, |this, cx| { - this.toggle_search_option(SearchOptions::CASE_SENSITIVE, cx) - }); - register_action::(workspace, |this: &mut BufferSearchBar, cx| { - this.toggle_search_option(SearchOptions::WHOLE_WORD, cx) - }); - register_action::(workspace, |this: &mut BufferSearchBar, cx| { - dbg!("Toggling"); - this.toggle_replace(&ToggleReplace, cx) - }); - // workspace.register_action(|workspace, _: &ToggleCaseSensitive, cx| { - // workspace.active_pane().update(cx, |this, cx| { - // this.toolbar().update(cx, |toolbar, cx| { - // let Some(search_bar) = toolbar.item_of_type::() else { - // return; - // }; - // search_bar.update(cx, |this, cx| { - // this.toggle_search_option(SearchOptions::CASE_SENSITIVE, cx); - // }) - // }) - // }); - // }); } pub fn new(cx: &mut ViewContext) -> Self { - dbg!("New"); let query_editor = cx.build_view(|cx| Editor::single_line(cx)); cx.subscribe(&query_editor, Self::on_query_editor_event) .detach(); @@ -463,7 +460,7 @@ impl BufferSearchBar { pub fn dismiss(&mut self, _: &Dismiss, cx: &mut ViewContext) { self.dismissed = true; - dbg!("Dismissed :("); + for searchable_item in self.searchable_items_with_matches.keys() { if let Some(searchable_item) = WeakSearchableItemHandle::upgrade(searchable_item.as_ref(), cx) @@ -495,10 +492,9 @@ impl BufferSearchBar { pub fn show(&mut self, cx: &mut ViewContext) -> bool { if self.active_searchable_item.is_none() { - dbg!("Hey"); return false; } - dbg!("not dismissed"); + self.dismissed = false; cx.notify(); cx.emit(Event::UpdateLocation); @@ -590,13 +586,7 @@ impl BufferSearchBar { self.update_matches(cx) } - fn render_action_button( - &self, - icon: &'static str, - cx: &mut ViewContext, - ) -> impl Component { - let tooltip = "Select All Matches"; - let theme = cx.theme(); + fn render_action_button(&self, cx: &mut ViewContext) -> impl Component { // let tooltip_style = theme.tooltip.clone(); // let style = theme.search.action_button.clone(); @@ -695,8 +685,13 @@ impl BufferSearchBar { .searchable_items_with_matches .get(&searchable_item.downgrade()) { - let new_match_index = searchable_item - .match_index_for_direction(matches, index, direction, count, cx); + let new_match_index = searchable_item.match_index_for_direction( + matches, + index, + direction, + dbg!(count), + cx, + ); searchable_item.update_matches(matches, cx); searchable_item.activate_match(new_match_index, matches, cx); } @@ -769,6 +764,7 @@ impl BufferSearchBar { } fn on_active_searchable_item_event(&mut self, event: &SearchEvent, cx: &mut ViewContext) { + dbg!(&event); match event { SearchEvent::MatchesInvalidated => { let _ = self.update_matches(cx); @@ -777,6 +773,12 @@ impl BufferSearchBar { } } + fn toggle_case_sensitive(&mut self, _: &ToggleCaseSensitive, cx: &mut ViewContext) { + self.toggle_search_option(SearchOptions::CASE_SENSITIVE, cx) + } + fn toggle_whole_word(&mut self, _: &ToggleWholeWord, cx: &mut ViewContext) { + self.toggle_search_option(SearchOptions::WHOLE_WORD, cx) + } fn clear_matches(&mut self, cx: &mut ViewContext) { let mut active_item_matches = None; for (searchable_item, matches) in self.searchable_items_with_matches.drain() { @@ -799,7 +801,7 @@ impl BufferSearchBar { let (done_tx, done_rx) = oneshot::channel(); let query = self.query(cx); self.pending_search.take(); - dbg!("update_matches"); + if let Some(active_searchable_item) = self.active_searchable_item.as_ref() { if query.is_empty() { self.active_match_index.take(); @@ -841,26 +843,23 @@ impl BufferSearchBar { .into(); self.active_search = Some(query.clone()); let query_text = query.as_str().to_string(); - dbg!(&query_text); + let matches = active_searchable_item.find_matches(query, cx); let active_searchable_item = active_searchable_item.downgrade(); self.pending_search = Some(cx.spawn(|this, mut cx| async move { let matches = matches.await; - //dbg!(&matches); + this.update(&mut cx, |this, cx| { - dbg!("Updating!!"); if let Some(active_searchable_item) = WeakSearchableItemHandle::upgrade(active_searchable_item.as_ref(), cx) { - dbg!("in if!!"); this.searchable_items_with_matches .insert(active_searchable_item.downgrade(), matches); this.update_match_index(cx); this.search_history.add(query_text); if !this.dismissed { - dbg!("Not dismissed"); let matches = this .searchable_items_with_matches .get(&active_searchable_item.downgrade()) diff --git a/crates/search2/src/search.rs b/crates/search2/src/search.rs index e4175e9e128ae785f378a8c1c2aecf92d601b3ae..233975839f847583b5e3fac4998b4cfc95e2f7d3 100644 --- a/crates/search2/src/search.rs +++ b/crates/search2/src/search.rs @@ -1,6 +1,6 @@ use bitflags::bitflags; pub use buffer_search::BufferSearchBar; -use gpui::{actions, Action, AnyElement, AppContext, Component, Element, Svg, View}; +use gpui::{actions, Action, AppContext, Component}; pub use mode::SearchMode; use project::search::SearchQuery; use ui::ButtonVariant; @@ -106,9 +106,8 @@ fn toggle_replace_button(active: bool) -> impl Component { .when(active, |button| button.variant(ButtonVariant::Filled)) } -fn replace_action( +fn render_replace_button( action: impl Action + 'static + Send + Sync, - name: &'static str, icon: ui::Icon, ) -> impl Component { // todo: add tooltip diff --git a/crates/search2/src/search_bar.rs b/crates/search2/src/search_bar.rs index 99735c5898479c0d52d229a5efd84371a5c6db47..1c77a03741de5b2e9f47324e1311a7a5830a6c75 100644 --- a/crates/search2/src/search_bar.rs +++ b/crates/search2/src/search_bar.rs @@ -1,28 +1,19 @@ use std::{borrow::Cow, sync::Arc}; use gpui::{div, Action, Component, ViewContext}; -use ui::{Button, ButtonVariant}; +use ui::{Button, ButtonVariant, IconButton}; use workspace::searchable::Direction; use crate::mode::{SearchMode, Side}; pub(super) fn render_nav_button( - icon: &'static str, + icon: ui::Icon, direction: Direction, + active: bool, on_click: impl Fn(&mut V, &mut ViewContext) + 'static + Send + Sync, cx: &mut ViewContext, ) -> impl Component { - let tooltip; - - match direction { - Direction::Prev => { - tooltip = "Select Previous Match"; - } - Direction::Next => { - tooltip = "Select Next Match"; - } - }; // let tooltip_style = cx.theme().tooltip.clone(); // let cursor_style = if active { // CursorStyle::PointingHand @@ -30,7 +21,7 @@ pub(super) fn render_nav_button( // CursorStyle::default() // }; // enum NavButton {} - Button::new(icon).on_click(Arc::new(on_click)) + IconButton::new("search-nav-button", icon).on_click(on_click) // MouseEventHandler::new::(direction as usize, cx, |state, cx| { // let theme = cx.theme(); // let style = theme