Start on project-wide find

This commit is contained in:
Antonio Scandurra 2022-02-23 12:38:36 +01:00
parent 39ebaebd83
commit fed6f708c0
6 changed files with 275 additions and 2 deletions

View file

@ -10,6 +10,7 @@ path = "src/find.rs"
collections = { path = "../collections" }
editor = { path = "../editor" }
gpui = { path = "../gpui" }
project = { path = "../project" }
theme = { path = "../theme" }
workspace = { path = "../workspace" }
aho-corasick = "0.7"

View file

@ -1,3 +1,5 @@
mod project_find;
use aho_corasick::AhoCorasickBuilder;
use anyhow::Result;
use collections::HashMap;

View file

@ -0,0 +1,46 @@
use crate::SearchMode;
use editor::MultiBuffer;
use gpui::{Entity, ModelContext, ModelHandle, Task};
use project::Project;
struct ProjectFind {
last_search: SearchParams,
project: ModelHandle<Project>,
excerpts: ModelHandle<MultiBuffer>,
pending_search: Task<Option<()>>,
}
#[derive(Default)]
struct SearchParams {
query: String,
regex: bool,
whole_word: bool,
case_sensitive: bool,
}
struct ProjectFindView {
model: ModelHandle<ProjectFind>,
}
impl Entity for ProjectFind {
type Event = ();
}
impl ProjectFind {
fn new(project: ModelHandle<Project>, cx: &mut ModelContext<Self>) -> Self {
let replica_id = project.read(cx).replica_id();
Self {
project,
last_search: Default::default(),
excerpts: cx.add_model(|_| MultiBuffer::new(replica_id)),
pending_search: Task::ready(None),
}
}
fn search(&mut self, params: SearchParams, cx: &mut ModelContext<Self>) {
self.pending_search = cx.spawn_weak(|this, cx| async move {
//
None
});
}
}

View file

@ -29,6 +29,7 @@ util = { path = "../util" }
anyhow = "1.0.38"
async-trait = "0.1"
futures = "0.3"
grep = "0.2"
ignore = "0.4"
lazy_static = "1.4.0"
libc = "0.2"

View file

@ -7,7 +7,7 @@ use anyhow::{anyhow, Context, Result};
use client::{proto, Client, PeerId, TypedEnvelope, User, UserStore};
use clock::ReplicaId;
use collections::{hash_map, HashMap, HashSet};
use futures::{future::Shared, Future, FutureExt};
use futures::{future::Shared, Future, FutureExt, StreamExt};
use fuzzy::{PathMatch, PathMatchCandidate, PathMatchCandidateSet};
use gpui::{
AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext, Task,
@ -16,7 +16,7 @@ use gpui::{
use language::{
range_from_lsp, Anchor, AnchorRangeExt, Bias, Buffer, CodeAction, CodeLabel, Completion,
Diagnostic, DiagnosticEntry, File as _, Language, LanguageRegistry, Operation, PointUtf16,
ToLspPosition, ToOffset, ToPointUtf16, Transaction,
Rope, ToLspPosition, ToOffset, ToPointUtf16, Transaction,
};
use lsp::{DiagnosticSeverity, DocumentHighlightKind, LanguageServer};
use lsp_command::*;
@ -2042,6 +2042,111 @@ impl Project {
)
}
pub fn search(&self, query: &str, cx: &mut ModelContext<Self>) {
if self.is_local() {
enum SearchItem {
Path(PathBuf),
Buffer((WeakModelHandle<Buffer>, Rope)),
}
let (queue_tx, queue_rx) = smol::channel::bounded(1024);
// Submit all worktree paths to the queue.
let snapshots = self
.strong_worktrees(cx)
.filter_map(|tree| {
let tree = tree.read(cx).as_local()?;
Some((tree.abs_path().clone(), tree.snapshot()))
})
.collect::<Vec<_>>();
cx.background()
.spawn({
let queue_tx = queue_tx.clone();
async move {
for (snapshot_abs_path, snapshot) in snapshots {
for file in snapshot.files(false, 0) {
if queue_tx
.send(SearchItem::Path(snapshot_abs_path.join(&file.path)))
.await
.is_err()
{
return;
}
}
}
}
})
.detach();
// Submit all the currently-open buffers that are dirty to the queue.
let buffers = self
.open_buffers
.values()
.filter_map(|buffer| {
if let OpenBuffer::Loaded(buffer) = buffer {
Some(buffer.clone())
} else {
None
}
})
.collect::<Vec<_>>();
cx.spawn_weak(|_, cx| async move {
for buffer in buffers.into_iter().filter_map(|buffer| buffer.upgrade(&cx)) {
let text = buffer.read_with(&cx, |buffer, _| {
if buffer.is_dirty() {
Some(buffer.as_rope().clone())
} else {
None
}
});
if let Some(text) = text {
if queue_tx
.send(SearchItem::Buffer((buffer.downgrade(), text)))
.await
.is_err()
{
return;
}
}
}
})
.detach();
let background = cx.background().clone();
cx.background()
.spawn(async move {
let workers = background.num_cpus();
background
.scoped(|scope| {
for _ in 0..workers {
let mut paths_rx = queue_rx.clone();
scope.spawn(async move {
while let Some(item) = paths_rx.next().await {
match item {
SearchItem::Path(_) => todo!(),
SearchItem::Buffer(_) => todo!(),
}
}
});
}
})
.await;
})
.detach();
// let multiline = query.contains('\n');
// let searcher = grep::searcher::SearcherBuilder::new()
// .multi_line(multiline)
// .build();
// searcher.search_path(
// "hey".to_string(),
// "/hello/world",
// grep::searcher::sinks::Lossy(|row, mat| {}),
// );
} else {
}
}
fn request_lsp<R: LspCommand>(
&self,
buffer_handle: ModelHandle<Buffer>,