Add query history and replace buttons
This commit is contained in:
parent
b11bfa8821
commit
c37faf0ab3
3 changed files with 113 additions and 124 deletions
|
@ -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::<Vec<_>>()
|
||||
// });
|
||||
// let next_query_keystrokes = cx.binding_for_action(&NextHistoryQuery {}).map(|binding| {
|
||||
// binding
|
||||
// .keystrokes()
|
||||
// .iter()
|
||||
// .map(|k| k.to_string())
|
||||
// .collect::<Vec<_>>()
|
||||
// });
|
||||
// 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::<Vec<_>>()
|
||||
});
|
||||
let next_query_keystrokes = cx
|
||||
.bindings_for_action(&NextHistoryQuery {})
|
||||
.into_iter()
|
||||
.next()
|
||||
.map(|binding| {
|
||||
binding
|
||||
.keystrokes()
|
||||
.iter()
|
||||
.map(|k| k.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
});
|
||||
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<Self>| {
|
||||
let nav_button_for_direction = |icon, direction, cx: &mut ViewContext<Self>| {
|
||||
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::<Self>(ReplaceAll, "Replace all", ui::Icon::ReplaceAll)
|
||||
});
|
||||
let replace_all = should_show_replace_input
|
||||
.then(|| super::render_replace_button::<Self>(ReplaceAll, ui::Icon::ReplaceAll));
|
||||
let replace_next = should_show_replace_input
|
||||
.then(|| super::replace_action::<Self>(ReplaceNext, "Replace next", ui::Icon::Replace));
|
||||
.then(|| super::render_replace_button::<Self>(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::<BufferSearchBar>().is_some() {
|
||||
if let Some(search_bar) = this.item_of_type::<BufferSearchBar>() {
|
||||
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<A: 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::<BufferSearchBar>() else {
|
||||
return;
|
||||
};
|
||||
search_bar.update(cx, |this, cx| update(this, cx))
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
register_action::<ToggleCaseSensitive>(workspace, |this, cx| {
|
||||
this.toggle_search_option(SearchOptions::CASE_SENSITIVE, cx)
|
||||
});
|
||||
register_action::<ToggleWholeWord>(workspace, |this: &mut BufferSearchBar, cx| {
|
||||
this.toggle_search_option(SearchOptions::WHOLE_WORD, cx)
|
||||
});
|
||||
register_action::<ToggleReplace>(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::<BufferSearchBar>() else {
|
||||
// return;
|
||||
// };
|
||||
// search_bar.update(cx, |this, cx| {
|
||||
// this.toggle_search_option(SearchOptions::CASE_SENSITIVE, cx);
|
||||
// })
|
||||
// })
|
||||
// });
|
||||
// });
|
||||
}
|
||||
pub fn new(cx: &mut ViewContext<Self>) -> 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>) {
|
||||
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<Self>) -> 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<Self>,
|
||||
) -> impl Component<Self> {
|
||||
let tooltip = "Select All Matches";
|
||||
let theme = cx.theme();
|
||||
fn render_action_button(&self, cx: &mut ViewContext<Self>) -> impl Component<Self> {
|
||||
// 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<Self>) {
|
||||
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>) {
|
||||
self.toggle_search_option(SearchOptions::CASE_SENSITIVE, cx)
|
||||
}
|
||||
fn toggle_whole_word(&mut self, _: &ToggleWholeWord, cx: &mut ViewContext<Self>) {
|
||||
self.toggle_search_option(SearchOptions::WHOLE_WORD, cx)
|
||||
}
|
||||
fn clear_matches(&mut self, cx: &mut ViewContext<Self>) {
|
||||
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())
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue