mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-28 20:01:33 +00:00
search: Add included and excluded history navigation support for project search (#15082)
Some checks are pending
CI / Check formatting and spelling (push) Waiting to run
CI / (macOS) Run Clippy and tests (push) Waiting to run
CI / (Linux) Run Clippy and tests (push) Waiting to run
CI / (Windows) Run Clippy and tests (push) Waiting to run
CI / Create a macOS bundle (push) Blocked by required conditions
CI / Create a Linux bundle (push) Blocked by required conditions
CI / Create arm64 Linux bundle (push) Blocked by required conditions
Deploy Docs / Deploy Docs (push) Waiting to run
Docs / Check formatting (push) Waiting to run
Some checks are pending
CI / Check formatting and spelling (push) Waiting to run
CI / (macOS) Run Clippy and tests (push) Waiting to run
CI / (Linux) Run Clippy and tests (push) Waiting to run
CI / (Windows) Run Clippy and tests (push) Waiting to run
CI / Create a macOS bundle (push) Blocked by required conditions
CI / Create a Linux bundle (push) Blocked by required conditions
CI / Create arm64 Linux bundle (push) Blocked by required conditions
Deploy Docs / Deploy Docs (push) Waiting to run
Docs / Check formatting (push) Waiting to run
Currently, had done the function for support included and excluded history navigate, but the code is more duplicate, I will dive into find better method to decrease the duplicate code. Release Notes: - N/A --------- Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com>
This commit is contained in:
parent
497356b2ba
commit
182f0f2ac8
3 changed files with 168 additions and 45 deletions
|
@ -66,7 +66,7 @@ use rpc::{
|
|||
proto::{AnyProtoClient, SSH_PROJECT_ID},
|
||||
ErrorCode,
|
||||
};
|
||||
use search::{SearchQuery, SearchResult};
|
||||
use search::{SearchInputKind, SearchQuery, SearchResult};
|
||||
use search_history::SearchHistory;
|
||||
use settings::{watch_config_file, Settings, SettingsLocation, SettingsStore};
|
||||
use smol::channel::Receiver;
|
||||
|
@ -167,6 +167,8 @@ pub struct Project {
|
|||
hosted_project_id: Option<ProjectId>,
|
||||
dev_server_project_id: Option<client::DevServerProjectId>,
|
||||
search_history: SearchHistory,
|
||||
search_included_history: SearchHistory,
|
||||
search_excluded_history: SearchHistory,
|
||||
snippets: Model<SnippetProvider>,
|
||||
last_formatting_failure: Option<String>,
|
||||
buffers_being_formatted: HashSet<BufferId>,
|
||||
|
@ -695,6 +697,8 @@ impl Project {
|
|||
remotely_created_buffers: Default::default(),
|
||||
last_formatting_failure: None,
|
||||
buffers_being_formatted: Default::default(),
|
||||
search_included_history: Self::new_search_history(),
|
||||
search_excluded_history: Self::new_search_history(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -898,6 +902,8 @@ impl Project {
|
|||
.dev_server_project_id
|
||||
.map(|dev_server_project_id| DevServerProjectId(dev_server_project_id)),
|
||||
search_history: Self::new_search_history(),
|
||||
search_included_history: Self::new_search_history(),
|
||||
search_excluded_history: Self::new_search_history(),
|
||||
environment: ProjectEnvironment::new(&worktree_store, None, cx),
|
||||
remotely_created_buffers: Arc::new(Mutex::new(RemotelyCreatedBuffers::default())),
|
||||
last_formatting_failure: None,
|
||||
|
@ -1349,12 +1355,20 @@ impl Project {
|
|||
&self.snippets
|
||||
}
|
||||
|
||||
pub fn search_history(&self) -> &SearchHistory {
|
||||
&self.search_history
|
||||
pub fn search_history(&self, kind: SearchInputKind) -> &SearchHistory {
|
||||
match kind {
|
||||
SearchInputKind::Query => &self.search_history,
|
||||
SearchInputKind::Include => &self.search_included_history,
|
||||
SearchInputKind::Exclude => &self.search_excluded_history,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn search_history_mut(&mut self) -> &mut SearchHistory {
|
||||
&mut self.search_history
|
||||
pub fn search_history_mut(&mut self, kind: SearchInputKind) -> &mut SearchHistory {
|
||||
match kind {
|
||||
SearchInputKind::Query => &mut self.search_history,
|
||||
SearchInputKind::Include => &mut self.search_included_history,
|
||||
SearchInputKind::Exclude => &mut self.search_excluded_history,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn collaborators(&self) -> &HashMap<proto::PeerId, Collaborator> {
|
||||
|
|
|
@ -25,6 +25,13 @@ pub enum SearchResult {
|
|||
LimitReached,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum SearchInputKind {
|
||||
Query,
|
||||
Include,
|
||||
Exclude,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SearchInputs {
|
||||
query: Arc<str>,
|
||||
|
|
|
@ -20,7 +20,11 @@ use gpui::{
|
|||
};
|
||||
use language::Buffer;
|
||||
use menu::Confirm;
|
||||
use project::{search::SearchQuery, search_history::SearchHistoryCursor, Project, ProjectPath};
|
||||
use project::{
|
||||
search::{SearchInputKind, SearchQuery},
|
||||
search_history::SearchHistoryCursor,
|
||||
Project, ProjectPath,
|
||||
};
|
||||
use settings::Settings;
|
||||
use std::{
|
||||
any::{Any, TypeId},
|
||||
|
@ -129,6 +133,8 @@ pub struct ProjectSearch {
|
|||
no_results: Option<bool>,
|
||||
limit_reached: bool,
|
||||
search_history_cursor: SearchHistoryCursor,
|
||||
search_included_history_cursor: SearchHistoryCursor,
|
||||
search_excluded_history_cursor: SearchHistoryCursor,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
|
@ -184,6 +190,8 @@ impl ProjectSearch {
|
|||
no_results: None,
|
||||
limit_reached: false,
|
||||
search_history_cursor: Default::default(),
|
||||
search_included_history_cursor: Default::default(),
|
||||
search_excluded_history_cursor: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,14 +209,42 @@ impl ProjectSearch {
|
|||
no_results: self.no_results,
|
||||
limit_reached: self.limit_reached,
|
||||
search_history_cursor: self.search_history_cursor.clone(),
|
||||
search_included_history_cursor: self.search_included_history_cursor.clone(),
|
||||
search_excluded_history_cursor: self.search_excluded_history_cursor.clone(),
|
||||
})
|
||||
}
|
||||
fn cursor(&self, kind: SearchInputKind) -> &SearchHistoryCursor {
|
||||
match kind {
|
||||
SearchInputKind::Query => &self.search_history_cursor,
|
||||
SearchInputKind::Include => &self.search_included_history_cursor,
|
||||
SearchInputKind::Exclude => &self.search_excluded_history_cursor,
|
||||
}
|
||||
}
|
||||
fn cursor_mut(&mut self, kind: SearchInputKind) -> &mut SearchHistoryCursor {
|
||||
match kind {
|
||||
SearchInputKind::Query => &mut self.search_history_cursor,
|
||||
SearchInputKind::Include => &mut self.search_included_history_cursor,
|
||||
SearchInputKind::Exclude => &mut self.search_excluded_history_cursor,
|
||||
}
|
||||
}
|
||||
|
||||
fn search(&mut self, query: SearchQuery, cx: &mut ModelContext<Self>) {
|
||||
let search = self.project.update(cx, |project, cx| {
|
||||
project
|
||||
.search_history_mut()
|
||||
.search_history_mut(SearchInputKind::Query)
|
||||
.add(&mut self.search_history_cursor, query.as_str().to_string());
|
||||
let included = query.as_inner().files_to_include().sources().join(",");
|
||||
if included.len() > 0 {
|
||||
project
|
||||
.search_history_mut(SearchInputKind::Include)
|
||||
.add(&mut self.search_included_history_cursor, included);
|
||||
}
|
||||
let excluded = query.as_inner().files_to_exclude().sources().join(",");
|
||||
if excluded.len() > 0 {
|
||||
project
|
||||
.search_history_mut(SearchInputKind::Exclude)
|
||||
.add(&mut self.search_excluded_history_cursor, excluded);
|
||||
}
|
||||
project.search(query.clone(), cx)
|
||||
});
|
||||
self.last_search_query_text = Some(query.as_str().to_string());
|
||||
|
@ -1072,8 +1108,7 @@ impl ProjectSearchView {
|
|||
}
|
||||
|
||||
fn set_query(&mut self, query: &str, cx: &mut ViewContext<Self>) {
|
||||
self.query_editor
|
||||
.update(cx, |query_editor, cx| query_editor.set_text(query, cx));
|
||||
self.set_search_editor(SearchInputKind::Query, query, cx);
|
||||
if EditorSettings::get_global(cx).use_smartcase_search {
|
||||
if !query.is_empty() {
|
||||
if self.search_options.contains(SearchOptions::CASE_SENSITIVE)
|
||||
|
@ -1085,6 +1120,16 @@ impl ProjectSearchView {
|
|||
}
|
||||
}
|
||||
|
||||
fn set_search_editor(&mut self, kind: SearchInputKind, text: &str, cx: &mut ViewContext<Self>) {
|
||||
let editor = match kind {
|
||||
SearchInputKind::Query => &self.query_editor,
|
||||
SearchInputKind::Include => &self.included_files_editor,
|
||||
|
||||
SearchInputKind::Exclude => &self.excluded_files_editor,
|
||||
};
|
||||
editor.update(cx, |included_editor, cx| included_editor.set_text(text, cx));
|
||||
}
|
||||
|
||||
fn focus_results_editor(&mut self, cx: &mut ViewContext<Self>) {
|
||||
self.query_editor.update(cx, |query_editor, cx| {
|
||||
let cursor = query_editor.selections.newest_anchor().head();
|
||||
|
@ -1388,20 +1433,36 @@ impl ProjectSearchBar {
|
|||
fn next_history_query(&mut self, _: &NextHistoryQuery, cx: &mut ViewContext<Self>) {
|
||||
if let Some(search_view) = self.active_project_search.as_ref() {
|
||||
search_view.update(cx, |search_view, cx| {
|
||||
let new_query = search_view.model.update(cx, |model, cx| {
|
||||
if let Some(new_query) = model.project.update(cx, |project, _| {
|
||||
project
|
||||
.search_history_mut()
|
||||
.next(&mut model.search_history_cursor)
|
||||
.map(str::to_string)
|
||||
}) {
|
||||
new_query
|
||||
} else {
|
||||
model.search_history_cursor.reset();
|
||||
String::new()
|
||||
for (editor, kind) in [
|
||||
(search_view.query_editor.clone(), SearchInputKind::Query),
|
||||
(
|
||||
search_view.included_files_editor.clone(),
|
||||
SearchInputKind::Include,
|
||||
),
|
||||
(
|
||||
search_view.excluded_files_editor.clone(),
|
||||
SearchInputKind::Exclude,
|
||||
),
|
||||
] {
|
||||
if editor.focus_handle(cx).is_focused(cx) {
|
||||
let new_query = search_view.model.update(cx, |model, cx| {
|
||||
let project = model.project.clone();
|
||||
|
||||
if let Some(new_query) = project.update(cx, |project, _| {
|
||||
project
|
||||
.search_history_mut(kind)
|
||||
.next(model.cursor_mut(kind))
|
||||
.map(str::to_string)
|
||||
}) {
|
||||
new_query
|
||||
} else {
|
||||
model.cursor_mut(kind).reset();
|
||||
String::new()
|
||||
}
|
||||
});
|
||||
search_view.set_search_editor(kind, &new_query, cx);
|
||||
}
|
||||
});
|
||||
search_view.set_query(&new_query, cx);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1409,30 +1470,45 @@ impl ProjectSearchBar {
|
|||
fn previous_history_query(&mut self, _: &PreviousHistoryQuery, cx: &mut ViewContext<Self>) {
|
||||
if let Some(search_view) = self.active_project_search.as_ref() {
|
||||
search_view.update(cx, |search_view, cx| {
|
||||
if search_view.query_editor.read(cx).text(cx).is_empty() {
|
||||
if let Some(new_query) = search_view
|
||||
.model
|
||||
.read(cx)
|
||||
.project
|
||||
.read(cx)
|
||||
.search_history()
|
||||
.current(&search_view.model.read(cx).search_history_cursor)
|
||||
.map(str::to_string)
|
||||
{
|
||||
search_view.set_query(&new_query, cx);
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (editor, kind) in [
|
||||
(search_view.query_editor.clone(), SearchInputKind::Query),
|
||||
(
|
||||
search_view.included_files_editor.clone(),
|
||||
SearchInputKind::Include,
|
||||
),
|
||||
(
|
||||
search_view.excluded_files_editor.clone(),
|
||||
SearchInputKind::Exclude,
|
||||
),
|
||||
] {
|
||||
if editor.focus_handle(cx).is_focused(cx) {
|
||||
if editor.read(cx).text(cx).is_empty() {
|
||||
if let Some(new_query) = search_view
|
||||
.model
|
||||
.read(cx)
|
||||
.project
|
||||
.read(cx)
|
||||
.search_history(kind)
|
||||
.current(&search_view.model.read(cx).cursor(kind))
|
||||
.map(str::to_string)
|
||||
{
|
||||
search_view.set_search_editor(kind, &new_query, cx);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(new_query) = search_view.model.update(cx, |model, cx| {
|
||||
model.project.update(cx, |project, _| {
|
||||
project
|
||||
.search_history_mut()
|
||||
.previous(&mut model.search_history_cursor)
|
||||
.map(str::to_string)
|
||||
})
|
||||
}) {
|
||||
search_view.set_query(&new_query, cx);
|
||||
if let Some(new_query) = search_view.model.update(cx, |model, cx| {
|
||||
let project = model.project.clone();
|
||||
project.update(cx, |project, _| {
|
||||
project
|
||||
.search_history_mut(kind)
|
||||
.previous(&mut model.cursor_mut(kind))
|
||||
.map(str::to_string)
|
||||
})
|
||||
}) {
|
||||
search_view.set_search_editor(kind, &new_query, cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1688,6 +1764,12 @@ impl Render for ProjectSearchBar {
|
|||
.border_1()
|
||||
.border_color(search.border_color_for(InputPanel::Include, cx))
|
||||
.rounded_lg()
|
||||
.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(self.render_text_input(&search.included_files_editor, cx)),
|
||||
)
|
||||
.child(
|
||||
|
@ -1701,6 +1783,12 @@ impl Render for ProjectSearchBar {
|
|||
.border_1()
|
||||
.border_color(search.border_color_for(InputPanel::Exclude, cx))
|
||||
.rounded_lg()
|
||||
.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(self.render_text_input(&search.excluded_files_editor, cx)),
|
||||
)
|
||||
.child(
|
||||
|
@ -2769,6 +2857,7 @@ pub mod tests {
|
|||
window
|
||||
.update(cx, |_, cx| {
|
||||
search_bar.update(cx, |search_bar, cx| {
|
||||
search_bar.focus_search(cx);
|
||||
search_bar.next_history_query(&NextHistoryQuery, cx);
|
||||
})
|
||||
})
|
||||
|
@ -2784,6 +2873,7 @@ pub mod tests {
|
|||
window
|
||||
.update(cx, |_, cx| {
|
||||
search_bar.update(cx, |search_bar, cx| {
|
||||
search_bar.focus_search(cx);
|
||||
search_bar.next_history_query(&NextHistoryQuery, cx);
|
||||
})
|
||||
})
|
||||
|
@ -2801,6 +2891,7 @@ pub mod tests {
|
|||
window
|
||||
.update(cx, |_, cx| {
|
||||
search_bar.update(cx, |search_bar, cx| {
|
||||
search_bar.focus_search(cx);
|
||||
search_bar.previous_history_query(&PreviousHistoryQuery, cx);
|
||||
});
|
||||
})
|
||||
|
@ -2818,6 +2909,7 @@ pub mod tests {
|
|||
window
|
||||
.update(cx, |_, cx| {
|
||||
search_bar.update(cx, |search_bar, cx| {
|
||||
search_bar.focus_search(cx);
|
||||
search_bar.previous_history_query(&PreviousHistoryQuery, cx);
|
||||
});
|
||||
})
|
||||
|
@ -2835,6 +2927,7 @@ pub mod tests {
|
|||
window
|
||||
.update(cx, |_, cx| {
|
||||
search_bar.update(cx, |search_bar, cx| {
|
||||
search_bar.focus_search(cx);
|
||||
search_bar.previous_history_query(&PreviousHistoryQuery, cx);
|
||||
});
|
||||
})
|
||||
|
@ -2850,6 +2943,7 @@ pub mod tests {
|
|||
window
|
||||
.update(cx, |_, cx| {
|
||||
search_bar.update(cx, |search_bar, cx| {
|
||||
search_bar.focus_search(cx);
|
||||
search_bar.previous_history_query(&PreviousHistoryQuery, cx);
|
||||
});
|
||||
})
|
||||
|
@ -2867,6 +2961,7 @@ pub mod tests {
|
|||
window
|
||||
.update(cx, |_, cx| {
|
||||
search_bar.update(cx, |search_bar, cx| {
|
||||
search_bar.focus_search(cx);
|
||||
search_bar.next_history_query(&NextHistoryQuery, cx);
|
||||
});
|
||||
})
|
||||
|
@ -2904,6 +2999,7 @@ pub mod tests {
|
|||
window
|
||||
.update(cx, |_, cx| {
|
||||
search_bar.update(cx, |search_bar, cx| {
|
||||
search_bar.focus_search(cx);
|
||||
search_bar.previous_history_query(&PreviousHistoryQuery, cx);
|
||||
});
|
||||
})
|
||||
|
@ -2919,6 +3015,7 @@ pub mod tests {
|
|||
window
|
||||
.update(cx, |_, cx| {
|
||||
search_bar.update(cx, |search_bar, cx| {
|
||||
search_bar.focus_search(cx);
|
||||
search_bar.previous_history_query(&PreviousHistoryQuery, cx);
|
||||
});
|
||||
})
|
||||
|
@ -2934,6 +3031,7 @@ pub mod tests {
|
|||
window
|
||||
.update(cx, |_, cx| {
|
||||
search_bar.update(cx, |search_bar, cx| {
|
||||
search_bar.focus_search(cx);
|
||||
search_bar.next_history_query(&NextHistoryQuery, cx);
|
||||
});
|
||||
})
|
||||
|
@ -2949,6 +3047,7 @@ pub mod tests {
|
|||
window
|
||||
.update(cx, |_, cx| {
|
||||
search_bar.update(cx, |search_bar, cx| {
|
||||
search_bar.focus_search(cx);
|
||||
search_bar.next_history_query(&NextHistoryQuery, cx);
|
||||
});
|
||||
})
|
||||
|
@ -2964,6 +3063,7 @@ pub mod tests {
|
|||
window
|
||||
.update(cx, |_, cx| {
|
||||
search_bar.update(cx, |search_bar, cx| {
|
||||
search_bar.focus_search(cx);
|
||||
search_bar.next_history_query(&NextHistoryQuery, cx);
|
||||
});
|
||||
})
|
||||
|
@ -3115,6 +3215,7 @@ pub mod tests {
|
|||
window
|
||||
.update(cx, |_, cx| {
|
||||
search_bar.update(cx, |search_bar, cx| {
|
||||
search_bar.focus_search(cx);
|
||||
search_bar.previous_history_query(&PreviousHistoryQuery, cx);
|
||||
})
|
||||
})
|
||||
|
@ -3126,6 +3227,7 @@ pub mod tests {
|
|||
window
|
||||
.update(cx, |_, cx| {
|
||||
search_bar.update(cx, |search_bar, cx| {
|
||||
search_bar.focus_search(cx);
|
||||
search_bar.next_history_query(&NextHistoryQuery, cx);
|
||||
})
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue