Fix project search unsaved edits (#30864)
Closes #30820 Release Notes: - Fixed an issue where entering a new search in the project search would drop unsaved edits in the project search buffer --------- Co-authored-by: Mark Janssen <20283+praseodym@users.noreply.github.com>
This commit is contained in:
parent
4d827924f0
commit
f56960ab5b
3 changed files with 151 additions and 54 deletions
|
@ -37,7 +37,7 @@ use ui::{
|
|||
Icon, IconButton, IconButtonShape, IconName, KeyBinding, Label, LabelCommon, LabelSize,
|
||||
Toggleable, Tooltip, h_flex, prelude::*, utils::SearchInputWidth, v_flex,
|
||||
};
|
||||
use util::paths::PathMatcher;
|
||||
use util::{ResultExt as _, paths::PathMatcher};
|
||||
use workspace::{
|
||||
DeploySearch, ItemNavHistory, NewSearch, ToolbarItemEvent, ToolbarItemLocation,
|
||||
ToolbarItemView, Workspace, WorkspaceId,
|
||||
|
@ -72,15 +72,18 @@ pub fn init(cx: &mut App) {
|
|||
);
|
||||
register_workspace_action(
|
||||
workspace,
|
||||
move |search_bar, _: &ToggleCaseSensitive, _, cx| {
|
||||
search_bar.toggle_search_option(SearchOptions::CASE_SENSITIVE, cx);
|
||||
move |search_bar, _: &ToggleCaseSensitive, window, cx| {
|
||||
search_bar.toggle_search_option(SearchOptions::CASE_SENSITIVE, window, cx);
|
||||
},
|
||||
);
|
||||
register_workspace_action(workspace, move |search_bar, _: &ToggleWholeWord, _, cx| {
|
||||
search_bar.toggle_search_option(SearchOptions::WHOLE_WORD, cx);
|
||||
});
|
||||
register_workspace_action(workspace, move |search_bar, _: &ToggleRegex, _, cx| {
|
||||
search_bar.toggle_search_option(SearchOptions::REGEX, cx);
|
||||
register_workspace_action(
|
||||
workspace,
|
||||
move |search_bar, _: &ToggleWholeWord, window, cx| {
|
||||
search_bar.toggle_search_option(SearchOptions::WHOLE_WORD, window, cx);
|
||||
},
|
||||
);
|
||||
register_workspace_action(workspace, move |search_bar, _: &ToggleRegex, window, cx| {
|
||||
search_bar.toggle_search_option(SearchOptions::REGEX, window, cx);
|
||||
});
|
||||
register_workspace_action(
|
||||
workspace,
|
||||
|
@ -1032,6 +1035,61 @@ impl ProjectSearchView {
|
|||
});
|
||||
}
|
||||
|
||||
fn prompt_to_save_if_dirty_then_search(
|
||||
&mut self,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<anyhow::Result<()>> {
|
||||
use workspace::AutosaveSetting;
|
||||
|
||||
let project = self.entity.read(cx).project.clone();
|
||||
|
||||
let can_autosave = self.results_editor.can_autosave(cx);
|
||||
let autosave_setting = self.results_editor.workspace_settings(cx).autosave;
|
||||
|
||||
let will_autosave = can_autosave
|
||||
&& matches!(
|
||||
autosave_setting,
|
||||
AutosaveSetting::OnFocusChange | AutosaveSetting::OnWindowChange
|
||||
);
|
||||
|
||||
let is_dirty = self.is_dirty(cx);
|
||||
|
||||
let should_confirm_save = !will_autosave && is_dirty;
|
||||
|
||||
cx.spawn_in(window, async move |this, cx| {
|
||||
let should_search = if should_confirm_save {
|
||||
let options = &["Save", "Don't Save", "Cancel"];
|
||||
let result_channel = this.update_in(cx, |_, window, cx| {
|
||||
window.prompt(
|
||||
gpui::PromptLevel::Warning,
|
||||
"Project search buffer contains unsaved edits. Do you want to save it?",
|
||||
None,
|
||||
options,
|
||||
cx,
|
||||
)
|
||||
})?;
|
||||
let result = result_channel.await?;
|
||||
let should_save = result == 0;
|
||||
if should_save {
|
||||
this.update_in(cx, |this, window, cx| this.save(true, project, window, cx))?
|
||||
.await
|
||||
.log_err();
|
||||
}
|
||||
let should_search = result != 2;
|
||||
should_search
|
||||
} else {
|
||||
true
|
||||
};
|
||||
if should_search {
|
||||
this.update(cx, |this, cx| {
|
||||
this.search(cx);
|
||||
})?;
|
||||
}
|
||||
anyhow::Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn search(&mut self, cx: &mut Context<Self>) {
|
||||
if let Some(query) = self.build_search_query(cx) {
|
||||
self.entity.update(cx, |model, cx| model.search(query, cx));
|
||||
|
@ -1503,7 +1561,9 @@ impl ProjectSearchBar {
|
|||
.is_focused(window)
|
||||
{
|
||||
cx.stop_propagation();
|
||||
search_view.search(cx);
|
||||
search_view
|
||||
.prompt_to_save_if_dirty_then_search(window, cx)
|
||||
.detach_and_log_err(cx);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1570,19 +1630,39 @@ impl ProjectSearchBar {
|
|||
});
|
||||
}
|
||||
|
||||
fn toggle_search_option(&mut self, option: SearchOptions, cx: &mut Context<Self>) -> bool {
|
||||
if let Some(search_view) = self.active_project_search.as_ref() {
|
||||
search_view.update(cx, |search_view, cx| {
|
||||
search_view.toggle_search_option(option, cx);
|
||||
if search_view.entity.read(cx).active_query.is_some() {
|
||||
search_view.search(cx);
|
||||
}
|
||||
});
|
||||
cx.notify();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
fn toggle_search_option(
|
||||
&mut self,
|
||||
option: SearchOptions,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> bool {
|
||||
if self.active_project_search.is_none() {
|
||||
return false;
|
||||
}
|
||||
|
||||
cx.spawn_in(window, async move |this, cx| {
|
||||
let task = this.update_in(cx, |this, window, cx| {
|
||||
let search_view = this.active_project_search.as_ref()?;
|
||||
search_view.update(cx, |search_view, cx| {
|
||||
search_view.toggle_search_option(option, cx);
|
||||
search_view
|
||||
.entity
|
||||
.read(cx)
|
||||
.active_query
|
||||
.is_some()
|
||||
.then(|| search_view.prompt_to_save_if_dirty_then_search(window, cx))
|
||||
})
|
||||
})?;
|
||||
if let Some(task) = task {
|
||||
task.await?;
|
||||
}
|
||||
this.update(cx, |_, cx| {
|
||||
cx.notify();
|
||||
})?;
|
||||
anyhow::Ok(())
|
||||
})
|
||||
.detach();
|
||||
true
|
||||
}
|
||||
|
||||
fn toggle_replace(&mut self, _: &ToggleReplace, window: &mut Window, cx: &mut Context<Self>) {
|
||||
|
@ -1621,19 +1701,33 @@ impl ProjectSearchBar {
|
|||
}
|
||||
|
||||
fn toggle_opened_only(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
|
||||
if let Some(search_view) = self.active_project_search.as_ref() {
|
||||
search_view.update(cx, |search_view, cx| {
|
||||
search_view.toggle_opened_only(window, cx);
|
||||
if search_view.entity.read(cx).active_query.is_some() {
|
||||
search_view.search(cx);
|
||||
}
|
||||
});
|
||||
|
||||
cx.notify();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
if self.active_project_search.is_none() {
|
||||
return false;
|
||||
}
|
||||
|
||||
cx.spawn_in(window, async move |this, cx| {
|
||||
let task = this.update_in(cx, |this, window, cx| {
|
||||
let search_view = this.active_project_search.as_ref()?;
|
||||
search_view.update(cx, |search_view, cx| {
|
||||
search_view.toggle_opened_only(window, cx);
|
||||
search_view
|
||||
.entity
|
||||
.read(cx)
|
||||
.active_query
|
||||
.is_some()
|
||||
.then(|| search_view.prompt_to_save_if_dirty_then_search(window, cx))
|
||||
})
|
||||
})?;
|
||||
if let Some(task) = task {
|
||||
task.await?;
|
||||
}
|
||||
this.update(cx, |_, cx| {
|
||||
cx.notify();
|
||||
})?;
|
||||
anyhow::Ok(())
|
||||
})
|
||||
.detach();
|
||||
true
|
||||
}
|
||||
|
||||
fn is_opened_only_enabled(&self, cx: &App) -> bool {
|
||||
|
@ -1860,22 +1954,22 @@ impl Render for ProjectSearchBar {
|
|||
.child(SearchOptions::CASE_SENSITIVE.as_button(
|
||||
self.is_option_enabled(SearchOptions::CASE_SENSITIVE, cx),
|
||||
focus_handle.clone(),
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_search_option(SearchOptions::CASE_SENSITIVE, cx);
|
||||
cx.listener(|this, _, window, cx| {
|
||||
this.toggle_search_option(SearchOptions::CASE_SENSITIVE, window, cx);
|
||||
}),
|
||||
))
|
||||
.child(SearchOptions::WHOLE_WORD.as_button(
|
||||
self.is_option_enabled(SearchOptions::WHOLE_WORD, cx),
|
||||
focus_handle.clone(),
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_search_option(SearchOptions::WHOLE_WORD, cx);
|
||||
cx.listener(|this, _, window, cx| {
|
||||
this.toggle_search_option(SearchOptions::WHOLE_WORD, window, cx);
|
||||
}),
|
||||
))
|
||||
.child(SearchOptions::REGEX.as_button(
|
||||
self.is_option_enabled(SearchOptions::REGEX, cx),
|
||||
focus_handle.clone(),
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_search_option(SearchOptions::REGEX, cx);
|
||||
cx.listener(|this, _, window, cx| {
|
||||
this.toggle_search_option(SearchOptions::REGEX, window, cx);
|
||||
}),
|
||||
)),
|
||||
);
|
||||
|
@ -2147,8 +2241,12 @@ impl Render for ProjectSearchBar {
|
|||
.search_options
|
||||
.contains(SearchOptions::INCLUDE_IGNORED),
|
||||
focus_handle.clone(),
|
||||
cx.listener(|this, _, _, cx| {
|
||||
this.toggle_search_option(SearchOptions::INCLUDE_IGNORED, cx);
|
||||
cx.listener(|this, _, window, cx| {
|
||||
this.toggle_search_option(
|
||||
SearchOptions::INCLUDE_IGNORED,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
|
@ -2188,11 +2286,11 @@ impl Render for ProjectSearchBar {
|
|||
.on_action(cx.listener(|this, action, window, cx| {
|
||||
this.toggle_replace(action, window, cx);
|
||||
}))
|
||||
.on_action(cx.listener(|this, _: &ToggleWholeWord, _, cx| {
|
||||
this.toggle_search_option(SearchOptions::WHOLE_WORD, cx);
|
||||
.on_action(cx.listener(|this, _: &ToggleWholeWord, window, cx| {
|
||||
this.toggle_search_option(SearchOptions::WHOLE_WORD, window, cx);
|
||||
}))
|
||||
.on_action(cx.listener(|this, _: &ToggleCaseSensitive, _, cx| {
|
||||
this.toggle_search_option(SearchOptions::CASE_SENSITIVE, cx);
|
||||
.on_action(cx.listener(|this, _: &ToggleCaseSensitive, window, cx| {
|
||||
this.toggle_search_option(SearchOptions::CASE_SENSITIVE, window, cx);
|
||||
}))
|
||||
.on_action(cx.listener(|this, action, window, cx| {
|
||||
if let Some(search) = this.active_project_search.as_ref() {
|
||||
|
@ -2209,8 +2307,8 @@ impl Render for ProjectSearchBar {
|
|||
}
|
||||
}))
|
||||
.when(search.filters_enabled, |this| {
|
||||
this.on_action(cx.listener(|this, _: &ToggleIncludeIgnored, _, cx| {
|
||||
this.toggle_search_option(SearchOptions::INCLUDE_IGNORED, cx);
|
||||
this.on_action(cx.listener(|this, _: &ToggleIncludeIgnored, window, cx| {
|
||||
this.toggle_search_option(SearchOptions::INCLUDE_IGNORED, window, cx);
|
||||
}))
|
||||
})
|
||||
.on_action(cx.listener(Self::select_next_match))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue