project_search: Add ability to search only for opened files (#16580)
Any suggestion? Release Notes: - add ability for project search only for opend files. --------- Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
This commit is contained in:
parent
403fdd6018
commit
400e503d9b
10 changed files with 192 additions and 20 deletions
|
@ -7238,8 +7238,11 @@ impl Project {
|
|||
) -> Receiver<SearchResult> {
|
||||
let (result_tx, result_rx) = smol::channel::unbounded();
|
||||
|
||||
let matching_buffers_rx =
|
||||
self.search_for_candidate_buffers(&query, MAX_SEARCH_RESULT_FILES + 1, cx);
|
||||
let matching_buffers_rx = if query.is_opened_only() {
|
||||
self.sort_candidate_buffers(&query, cx)
|
||||
} else {
|
||||
self.search_for_candidate_buffers(&query, MAX_SEARCH_RESULT_FILES + 1, cx)
|
||||
};
|
||||
|
||||
cx.spawn(|_, cx| async move {
|
||||
let mut range_count = 0;
|
||||
|
@ -7317,6 +7320,48 @@ impl Project {
|
|||
}
|
||||
}
|
||||
|
||||
fn sort_candidate_buffers(
|
||||
&mut self,
|
||||
search_query: &SearchQuery,
|
||||
cx: &mut ModelContext<Project>,
|
||||
) -> Receiver<Model<Buffer>> {
|
||||
let worktree_store = self.worktree_store.read(cx);
|
||||
let mut buffers = search_query
|
||||
.buffers()
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.filter(|buffer| {
|
||||
let b = buffer.read(cx);
|
||||
if let Some(file) = b.file() {
|
||||
if !search_query.file_matches(file.path()) {
|
||||
return false;
|
||||
}
|
||||
if let Some(entry) = b
|
||||
.entry_id(cx)
|
||||
.and_then(|entry_id| worktree_store.entry_for_id(entry_id, cx))
|
||||
{
|
||||
if entry.is_ignored && !search_query.include_ignored() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let (tx, rx) = smol::channel::unbounded();
|
||||
buffers.sort_by(|a, b| match (a.read(cx).file(), b.read(cx).file()) {
|
||||
(None, None) => a.read(cx).remote_id().cmp(&b.read(cx).remote_id()),
|
||||
(None, Some(_)) => std::cmp::Ordering::Less,
|
||||
(Some(_), None) => std::cmp::Ordering::Greater,
|
||||
(Some(a), Some(b)) => compare_paths((a.path(), true), (b.path(), true)),
|
||||
});
|
||||
for buffer in buffers {
|
||||
tx.send_blocking(buffer.clone()).unwrap()
|
||||
}
|
||||
|
||||
rx
|
||||
}
|
||||
|
||||
fn search_for_candidate_buffers_remote(
|
||||
&mut self,
|
||||
query: &SearchQuery,
|
||||
|
|
|
@ -3941,7 +3941,8 @@ async fn test_search(cx: &mut gpui::TestAppContext) {
|
|||
true,
|
||||
false,
|
||||
Default::default(),
|
||||
Default::default()
|
||||
Default::default(),
|
||||
None
|
||||
)
|
||||
.unwrap(),
|
||||
cx
|
||||
|
@ -3974,7 +3975,8 @@ async fn test_search(cx: &mut gpui::TestAppContext) {
|
|||
true,
|
||||
false,
|
||||
Default::default(),
|
||||
Default::default()
|
||||
Default::default(),
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
cx
|
||||
|
@ -4017,7 +4019,8 @@ async fn test_search_with_inclusions(cx: &mut gpui::TestAppContext) {
|
|||
true,
|
||||
false,
|
||||
PathMatcher::new(&["*.odd".to_owned()]).unwrap(),
|
||||
Default::default()
|
||||
Default::default(),
|
||||
None
|
||||
)
|
||||
.unwrap(),
|
||||
cx
|
||||
|
@ -4037,7 +4040,8 @@ async fn test_search_with_inclusions(cx: &mut gpui::TestAppContext) {
|
|||
true,
|
||||
false,
|
||||
PathMatcher::new(&["*.rs".to_owned()]).unwrap(),
|
||||
Default::default()
|
||||
Default::default(),
|
||||
None
|
||||
)
|
||||
.unwrap(),
|
||||
cx
|
||||
|
@ -4063,6 +4067,7 @@ async fn test_search_with_inclusions(cx: &mut gpui::TestAppContext) {
|
|||
PathMatcher::new(&["*.ts".to_owned(), "*.odd".to_owned()]).unwrap(),
|
||||
|
||||
Default::default(),
|
||||
None,
|
||||
).unwrap(),
|
||||
cx
|
||||
)
|
||||
|
@ -4087,6 +4092,7 @@ async fn test_search_with_inclusions(cx: &mut gpui::TestAppContext) {
|
|||
PathMatcher::new(&["*.rs".to_owned(), "*.ts".to_owned(), "*.odd".to_owned()]).unwrap(),
|
||||
|
||||
Default::default(),
|
||||
None,
|
||||
).unwrap(),
|
||||
cx
|
||||
)
|
||||
|
@ -4131,6 +4137,7 @@ async fn test_search_with_exclusions(cx: &mut gpui::TestAppContext) {
|
|||
false,
|
||||
Default::default(),
|
||||
PathMatcher::new(&["*.odd".to_owned()]).unwrap(),
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
cx
|
||||
|
@ -4155,7 +4162,8 @@ async fn test_search_with_exclusions(cx: &mut gpui::TestAppContext) {
|
|||
true,
|
||||
false,
|
||||
Default::default(),
|
||||
PathMatcher::new(&["*.rs".to_owned()]).unwrap()
|
||||
PathMatcher::new(&["*.rs".to_owned()]).unwrap(),
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
cx
|
||||
|
@ -4180,6 +4188,7 @@ async fn test_search_with_exclusions(cx: &mut gpui::TestAppContext) {
|
|||
Default::default(),
|
||||
|
||||
PathMatcher::new(&["*.ts".to_owned(), "*.odd".to_owned()]).unwrap(),
|
||||
None,
|
||||
|
||||
).unwrap(),
|
||||
cx
|
||||
|
@ -4204,6 +4213,7 @@ async fn test_search_with_exclusions(cx: &mut gpui::TestAppContext) {
|
|||
Default::default(),
|
||||
|
||||
PathMatcher::new(&["*.rs".to_owned(), "*.ts".to_owned(), "*.odd".to_owned()]).unwrap(),
|
||||
None,
|
||||
|
||||
).unwrap(),
|
||||
cx
|
||||
|
@ -4243,6 +4253,7 @@ async fn test_search_with_exclusions_and_inclusions(cx: &mut gpui::TestAppContex
|
|||
false,
|
||||
PathMatcher::new(&["*.odd".to_owned()]).unwrap(),
|
||||
PathMatcher::new(&["*.odd".to_owned()]).unwrap(),
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
cx
|
||||
|
@ -4263,6 +4274,7 @@ async fn test_search_with_exclusions_and_inclusions(cx: &mut gpui::TestAppContex
|
|||
false,
|
||||
PathMatcher::new(&["*.ts".to_owned()]).unwrap(),
|
||||
PathMatcher::new(&["*.ts".to_owned()]).unwrap(),
|
||||
None,
|
||||
).unwrap(),
|
||||
cx
|
||||
)
|
||||
|
@ -4282,6 +4294,7 @@ async fn test_search_with_exclusions_and_inclusions(cx: &mut gpui::TestAppContex
|
|||
false,
|
||||
PathMatcher::new(&["*.ts".to_owned(), "*.odd".to_owned()]).unwrap(),
|
||||
PathMatcher::new(&["*.ts".to_owned(), "*.odd".to_owned()]).unwrap(),
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
cx
|
||||
|
@ -4302,6 +4315,7 @@ async fn test_search_with_exclusions_and_inclusions(cx: &mut gpui::TestAppContex
|
|||
false,
|
||||
PathMatcher::new(&["*.ts".to_owned(), "*.odd".to_owned()]).unwrap(),
|
||||
PathMatcher::new(&["*.rs".to_owned(), "*.odd".to_owned()]).unwrap(),
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
cx
|
||||
|
@ -4354,7 +4368,8 @@ async fn test_search_multiple_worktrees_with_inclusions(cx: &mut gpui::TestAppCo
|
|||
true,
|
||||
false,
|
||||
PathMatcher::new(&["worktree-a/*.rs".to_owned()]).unwrap(),
|
||||
Default::default()
|
||||
Default::default(),
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
cx
|
||||
|
@ -4373,7 +4388,8 @@ async fn test_search_multiple_worktrees_with_inclusions(cx: &mut gpui::TestAppCo
|
|||
true,
|
||||
false,
|
||||
PathMatcher::new(&["worktree-b/*.rs".to_owned()]).unwrap(),
|
||||
Default::default()
|
||||
Default::default(),
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
cx
|
||||
|
@ -4393,7 +4409,8 @@ async fn test_search_multiple_worktrees_with_inclusions(cx: &mut gpui::TestAppCo
|
|||
true,
|
||||
false,
|
||||
PathMatcher::new(&["*.ts".to_owned()]).unwrap(),
|
||||
Default::default()
|
||||
Default::default(),
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
cx
|
||||
|
@ -4447,7 +4464,8 @@ async fn test_search_in_gitignored_dirs(cx: &mut gpui::TestAppContext) {
|
|||
false,
|
||||
false,
|
||||
Default::default(),
|
||||
Default::default()
|
||||
Default::default(),
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
cx
|
||||
|
@ -4468,7 +4486,8 @@ async fn test_search_in_gitignored_dirs(cx: &mut gpui::TestAppContext) {
|
|||
false,
|
||||
true,
|
||||
Default::default(),
|
||||
Default::default()
|
||||
Default::default(),
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
cx
|
||||
|
@ -4508,6 +4527,7 @@ async fn test_search_in_gitignored_dirs(cx: &mut gpui::TestAppContext) {
|
|||
true,
|
||||
files_to_include,
|
||||
files_to_exclude,
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
cx
|
||||
|
@ -4554,6 +4574,7 @@ async fn test_search_ordering(cx: &mut gpui::TestAppContext) {
|
|||
true,
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
None,
|
||||
)
|
||||
.unwrap(),
|
||||
cx,
|
||||
|
|
|
@ -30,6 +30,7 @@ pub struct SearchInputs {
|
|||
query: Arc<str>,
|
||||
files_to_include: PathMatcher,
|
||||
files_to_exclude: PathMatcher,
|
||||
buffers: Option<Vec<Model<Buffer>>>,
|
||||
}
|
||||
|
||||
impl SearchInputs {
|
||||
|
@ -42,6 +43,9 @@ impl SearchInputs {
|
|||
pub fn files_to_exclude(&self) -> &PathMatcher {
|
||||
&self.files_to_exclude
|
||||
}
|
||||
pub fn buffers(&self) -> &Option<Vec<Model<Buffer>>> {
|
||||
&self.buffers
|
||||
}
|
||||
}
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum SearchQuery {
|
||||
|
@ -73,6 +77,7 @@ impl SearchQuery {
|
|||
include_ignored: bool,
|
||||
files_to_include: PathMatcher,
|
||||
files_to_exclude: PathMatcher,
|
||||
buffers: Option<Vec<Model<Buffer>>>,
|
||||
) -> Result<Self> {
|
||||
let query = query.to_string();
|
||||
let search = AhoCorasickBuilder::new()
|
||||
|
@ -82,6 +87,7 @@ impl SearchQuery {
|
|||
query: query.into(),
|
||||
files_to_exclude,
|
||||
files_to_include,
|
||||
buffers,
|
||||
};
|
||||
Ok(Self::Text {
|
||||
search: Arc::new(search),
|
||||
|
@ -100,6 +106,7 @@ impl SearchQuery {
|
|||
include_ignored: bool,
|
||||
files_to_include: PathMatcher,
|
||||
files_to_exclude: PathMatcher,
|
||||
buffers: Option<Vec<Model<Buffer>>>,
|
||||
) -> Result<Self> {
|
||||
let mut query = query.to_string();
|
||||
let initial_query = Arc::from(query.as_str());
|
||||
|
@ -120,6 +127,7 @@ impl SearchQuery {
|
|||
query: initial_query,
|
||||
files_to_exclude,
|
||||
files_to_include,
|
||||
buffers,
|
||||
};
|
||||
Ok(Self::Regex {
|
||||
regex,
|
||||
|
@ -141,6 +149,7 @@ impl SearchQuery {
|
|||
message.include_ignored,
|
||||
deserialize_path_matches(&message.files_to_include)?,
|
||||
deserialize_path_matches(&message.files_to_exclude)?,
|
||||
None,
|
||||
)
|
||||
} else {
|
||||
Self::text(
|
||||
|
@ -150,6 +159,7 @@ impl SearchQuery {
|
|||
message.include_ignored,
|
||||
deserialize_path_matches(&message.files_to_include)?,
|
||||
deserialize_path_matches(&message.files_to_exclude)?,
|
||||
None,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -163,6 +173,7 @@ impl SearchQuery {
|
|||
message.include_ignored,
|
||||
deserialize_path_matches(&message.files_to_include)?,
|
||||
deserialize_path_matches(&message.files_to_exclude)?,
|
||||
None, // search opened only don't need search remote
|
||||
)
|
||||
} else {
|
||||
Self::text(
|
||||
|
@ -172,6 +183,7 @@ impl SearchQuery {
|
|||
message.include_ignored,
|
||||
deserialize_path_matches(&message.files_to_include)?,
|
||||
deserialize_path_matches(&message.files_to_exclude)?,
|
||||
None, // search opened only don't need search remote
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -420,6 +432,14 @@ impl SearchQuery {
|
|||
self.as_inner().files_to_exclude()
|
||||
}
|
||||
|
||||
pub fn buffers(&self) -> Option<&Vec<Model<Buffer>>> {
|
||||
self.as_inner().buffers.as_ref()
|
||||
}
|
||||
|
||||
pub fn is_opened_only(&self) -> bool {
|
||||
self.as_inner().buffers.is_some()
|
||||
}
|
||||
|
||||
pub fn filters_path(&self) -> bool {
|
||||
!(self.files_to_exclude().sources().is_empty()
|
||||
&& self.files_to_include().sources().is_empty())
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue