Detailed changes
@@ -2097,6 +2097,10 @@ dependencies = [
[[package]]
name = "fuzzy"
version = "0.1.0"
+dependencies = [
+ "gpui",
+ "util",
+]
[[package]]
name = "generator"
@@ -3674,6 +3678,36 @@ dependencies = [
"unicode-xid",
]
+[[package]]
+name = "project"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "async-trait",
+ "buffer",
+ "clock",
+ "fsevent",
+ "futures",
+ "fuzzy",
+ "gpui",
+ "ignore",
+ "lazy_static",
+ "libc",
+ "log",
+ "parking_lot",
+ "postage",
+ "rand 0.8.3",
+ "rpc",
+ "rpc_client",
+ "serde 1.0.125",
+ "serde_json 1.0.64",
+ "smol",
+ "sum_tree",
+ "tempdir",
+ "toml 0.5.8",
+ "util",
+]
+
[[package]]
name = "prost"
version = "0.8.0"
@@ -5975,36 +6009,6 @@ dependencies = [
"winapi 0.3.9",
]
-[[package]]
-name = "worktree"
-version = "0.1.0"
-dependencies = [
- "anyhow",
- "async-trait",
- "buffer",
- "clock",
- "fsevent",
- "futures",
- "fuzzy",
- "gpui",
- "ignore",
- "lazy_static",
- "libc",
- "log",
- "parking_lot",
- "postage",
- "rand 0.8.3",
- "rpc",
- "rpc_client",
- "serde 1.0.125",
- "serde_json 1.0.64",
- "smol",
- "sum_tree",
- "tempdir",
- "toml 0.5.8",
- "util",
-]
-
[[package]]
name = "wyz"
version = "0.2.0"
@@ -6070,6 +6074,7 @@ dependencies = [
"num_cpus",
"parking_lot",
"postage",
+ "project",
"rand 0.8.3",
"rpc",
"rpc_client",
@@ -6093,7 +6098,6 @@ dependencies = [
"unindent",
"url",
"util",
- "worktree",
]
[[package]]
@@ -2,3 +2,7 @@
name = "fuzzy"
version = "0.1.0"
edition = "2018"
+
+[dependencies]
+gpui = { path = "../gpui" }
+util = { path = "../util" }
@@ -1,8 +1,9 @@
mod char_bag;
+use gpui::executor;
use std::{
borrow::Cow,
- cmp::Ordering,
+ cmp::{self, Ordering},
path::Path,
sync::atomic::{self, AtomicBool},
sync::Arc,
@@ -58,6 +59,14 @@ pub struct StringMatchCandidate {
pub char_bag: CharBag,
}
+pub trait PathMatchCandidateSet<'a>: Send + Sync {
+ type Candidates: Iterator<Item = PathMatchCandidate<'a>>;
+ fn id(&self) -> usize;
+ fn len(&self) -> usize;
+ fn prefix(&self) -> Arc<str>;
+ fn candidates(&'a self, start: usize) -> Self::Candidates;
+}
+
impl Match for PathMatch {
fn score(&self) -> f64 {
self.score
@@ -152,6 +161,140 @@ impl Ord for PathMatch {
}
}
+pub async fn match_strings(
+ candidates: &[StringMatchCandidate],
+ query: &str,
+ smart_case: bool,
+ max_results: usize,
+ cancel_flag: &AtomicBool,
+ background: Arc<executor::Background>,
+) -> Vec<StringMatch> {
+ let lowercase_query = query.to_lowercase().chars().collect::<Vec<_>>();
+ let query = query.chars().collect::<Vec<_>>();
+
+ let lowercase_query = &lowercase_query;
+ let query = &query;
+ let query_char_bag = CharBag::from(&lowercase_query[..]);
+
+ let num_cpus = background.num_cpus().min(candidates.len());
+ let segment_size = (candidates.len() + num_cpus - 1) / num_cpus;
+ let mut segment_results = (0..num_cpus)
+ .map(|_| Vec::with_capacity(max_results))
+ .collect::<Vec<_>>();
+
+ background
+ .scoped(|scope| {
+ for (segment_idx, results) in segment_results.iter_mut().enumerate() {
+ let cancel_flag = &cancel_flag;
+ scope.spawn(async move {
+ let segment_start = segment_idx * segment_size;
+ let segment_end = segment_start + segment_size;
+ let mut matcher = Matcher::new(
+ query,
+ lowercase_query,
+ query_char_bag,
+ smart_case,
+ max_results,
+ );
+ matcher.match_strings(
+ &candidates[segment_start..segment_end],
+ results,
+ cancel_flag,
+ );
+ });
+ }
+ })
+ .await;
+
+ let mut results = Vec::new();
+ for segment_result in segment_results {
+ if results.is_empty() {
+ results = segment_result;
+ } else {
+ util::extend_sorted(&mut results, segment_result, max_results, |a, b| b.cmp(&a));
+ }
+ }
+ results
+}
+
+pub async fn match_paths<'a, Set: PathMatchCandidateSet<'a>>(
+ candidate_sets: &'a [Set],
+ query: &str,
+ smart_case: bool,
+ max_results: usize,
+ cancel_flag: &AtomicBool,
+ background: Arc<executor::Background>,
+) -> Vec<PathMatch> {
+ let path_count: usize = candidate_sets.iter().map(|s| s.len()).sum();
+ if path_count == 0 {
+ return Vec::new();
+ }
+
+ let lowercase_query = query.to_lowercase().chars().collect::<Vec<_>>();
+ let query = query.chars().collect::<Vec<_>>();
+
+ let lowercase_query = &lowercase_query;
+ let query = &query;
+ let query_char_bag = CharBag::from(&lowercase_query[..]);
+
+ let num_cpus = background.num_cpus().min(path_count);
+ let segment_size = (path_count + num_cpus - 1) / num_cpus;
+ let mut segment_results = (0..num_cpus)
+ .map(|_| Vec::with_capacity(max_results))
+ .collect::<Vec<_>>();
+
+ background
+ .scoped(|scope| {
+ for (segment_idx, results) in segment_results.iter_mut().enumerate() {
+ scope.spawn(async move {
+ let segment_start = segment_idx * segment_size;
+ let segment_end = segment_start + segment_size;
+ let mut matcher = Matcher::new(
+ query,
+ lowercase_query,
+ query_char_bag,
+ smart_case,
+ max_results,
+ );
+
+ let mut tree_start = 0;
+ for candidate_set in candidate_sets {
+ let tree_end = tree_start + candidate_set.len();
+
+ if tree_start < segment_end && segment_start < tree_end {
+ let start = cmp::max(tree_start, segment_start) - tree_start;
+ let end = cmp::min(tree_end, segment_end) - tree_start;
+ let candidates = candidate_set.candidates(start).take(end - start);
+
+ matcher.match_paths(
+ candidate_set.id(),
+ candidate_set.prefix(),
+ candidates,
+ results,
+ &cancel_flag,
+ );
+ }
+ if tree_end >= segment_end {
+ break;
+ }
+ tree_start = tree_end;
+ }
+ })
+ }
+ })
+ .await;
+
+ let mut results = Vec::new();
+ for segment_result in segment_results {
+ if results.is_empty() {
+ results = segment_result;
+ } else {
+ util::extend_sorted(&mut results, segment_result, max_results, |a, b| b.cmp(&a));
+ }
+ }
+ results
+}
+
impl<'a> Matcher<'a> {
pub fn new(
query: &'a [char],
@@ -194,11 +337,11 @@ impl<'a> Matcher<'a> {
)
}
- pub fn match_paths(
+ pub fn match_paths<'c: 'a>(
&mut self,
tree_id: usize,
path_prefix: Arc<str>,
- path_entries: impl Iterator<Item = PathMatchCandidate<'a>>,
+ path_entries: impl Iterator<Item = PathMatchCandidate<'c>>,
results: &mut Vec<PathMatch>,
cancel_flag: &AtomicBool,
) {
@@ -1,5 +1,5 @@
[package]
-name = "worktree"
+name = "project"
version = "0.1.0"
edition = "2018"
@@ -1,10 +1,11 @@
-use crate::{
- fuzzy::{self, PathMatch},
- AppState,
-};
+pub mod fs;
+mod ignore;
+mod worktree;
+
use anyhow::Result;
use buffer::LanguageRegistry;
use futures::Future;
+use fuzzy::{self, PathMatch, PathMatchCandidate, PathMatchCandidateSet};
use gpui::{AppContext, Entity, ModelContext, ModelHandle, Task};
use rpc_client as rpc;
use std::{
@@ -12,7 +13,9 @@ use std::{
sync::{atomic::AtomicBool, Arc},
};
use util::TryFutureExt as _;
-use worktree::{fs::Fs, Worktree};
+
+pub use fs::*;
+pub use worktree::*;
pub struct Project {
worktrees: Vec<ModelHandle<Worktree>>,
@@ -40,13 +43,13 @@ pub struct ProjectEntry {
}
impl Project {
- pub fn new(app_state: &AppState) -> Self {
+ pub fn new(languages: Arc<LanguageRegistry>, rpc: Arc<rpc::Client>, fs: Arc<dyn Fs>) -> Self {
Self {
worktrees: Default::default(),
active_entry: None,
- languages: app_state.languages.clone(),
- rpc: app_state.rpc.clone(),
- fs: app_state.fs.clone(),
+ languages,
+ rpc,
+ fs,
}
}
@@ -207,18 +210,22 @@ impl Project {
cancel_flag: &'a AtomicBool,
cx: &AppContext,
) -> impl 'a + Future<Output = Vec<PathMatch>> {
- let snapshots = self
+ let include_root_name = self.worktrees.len() > 1;
+ let candidate_sets = self
.worktrees
.iter()
- .map(|worktree| worktree.read(cx).snapshot())
+ .map(|worktree| CandidateSet {
+ snapshot: worktree.read(cx).snapshot(),
+ include_ignored,
+ include_root_name,
+ })
.collect::<Vec<_>>();
- let background = cx.background().clone();
+ let background = cx.background().clone();
async move {
fuzzy::match_paths(
- snapshots.as_slice(),
+ candidate_sets.as_slice(),
query,
- include_ignored,
smart_case,
max_results,
cancel_flag,
@@ -229,6 +236,65 @@ impl Project {
}
}
+struct CandidateSet {
+ snapshot: Snapshot,
+ include_ignored: bool,
+ include_root_name: bool,
+}
+
+impl<'a> PathMatchCandidateSet<'a> for CandidateSet {
+ type Candidates = CandidateSetIter<'a>;
+
+ fn id(&self) -> usize {
+ self.snapshot.id()
+ }
+
+ fn len(&self) -> usize {
+ if self.include_ignored {
+ self.snapshot.file_count()
+ } else {
+ self.snapshot.visible_file_count()
+ }
+ }
+
+ fn prefix(&self) -> Arc<str> {
+ if self.snapshot.root_entry().map_or(false, |e| e.is_file()) {
+ self.snapshot.root_name().into()
+ } else if self.include_root_name {
+ format!("{}/", self.snapshot.root_name()).into()
+ } else {
+ "".into()
+ }
+ }
+
+ fn candidates(&'a self, start: usize) -> Self::Candidates {
+ CandidateSetIter {
+ traversal: self.snapshot.files(self.include_ignored, start),
+ }
+ }
+}
+
+struct CandidateSetIter<'a> {
+ traversal: Traversal<'a>,
+}
+
+impl<'a> Iterator for CandidateSetIter<'a> {
+ type Item = PathMatchCandidate<'a>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.traversal.next().map(|entry| {
+ if let EntryKind::File(char_bag) = entry.kind {
+ PathMatchCandidate {
+ path: &entry.path,
+ char_bag,
+ }
+ } else {
+ unreachable!()
+ }
+ })
+ }
+}
+
impl Entity for Project {
type Event = Event;
}
@@ -236,16 +302,15 @@ impl Entity for Project {
#[cfg(test)]
mod tests {
use super::*;
- use crate::test::test_app_state;
+ use buffer::LanguageRegistry;
+ use fs::RealFs;
+ use gpui::TestAppContext;
use serde_json::json;
use std::{os::unix, path::PathBuf};
use util::test::temp_tree;
- use worktree::fs::RealFs;
#[gpui::test]
async fn test_populate_and_search(mut cx: gpui::TestAppContext) {
- let mut app_state = cx.update(test_app_state);
- Arc::get_mut(&mut app_state).unwrap().fs = Arc::new(RealFs);
let dir = temp_tree(json!({
"root": {
"apple": "",
@@ -269,7 +334,8 @@ mod tests {
)
.unwrap();
- let project = cx.add_model(|_| Project::new(app_state.as_ref()));
+ let project = build_project(&mut cx);
+
let tree = project
.update(&mut cx, |project, cx| {
project.add_local_worktree(&root_link_path, cx)
@@ -308,8 +374,6 @@ mod tests {
#[gpui::test]
async fn test_search_worktree_without_files(mut cx: gpui::TestAppContext) {
- let mut app_state = cx.update(test_app_state);
- Arc::get_mut(&mut app_state).unwrap().fs = Arc::new(RealFs);
let dir = temp_tree(json!({
"root": {
"dir1": {},
@@ -319,7 +383,7 @@ mod tests {
}
}));
- let project = cx.add_model(|_| Project::new(app_state.as_ref()));
+ let project = build_project(&mut cx);
let tree = project
.update(&mut cx, |project, cx| {
project.add_local_worktree(&dir.path(), cx)
@@ -339,4 +403,11 @@ mod tests {
assert!(results.is_empty());
}
+
+ fn build_project(cx: &mut TestAppContext) -> ModelHandle<Project> {
+ let languages = Arc::new(LanguageRegistry::new());
+ let fs = Arc::new(RealFs);
+ let rpc = rpc::Client::new();
+ cx.add_model(|_| Project::new(languages, rpc, fs))
+ }
}
@@ -1,12 +1,11 @@
-pub mod fs;
-mod ignore;
-
-use self::ignore::IgnoreStack;
+use super::{
+ fs::{self, Fs},
+ ignore::IgnoreStack,
+};
use ::ignore::gitignore::{Gitignore, GitignoreBuilder};
use anyhow::{anyhow, Result};
use buffer::{self, Buffer, History, LanguageRegistry, Operation, Rope};
use clock::ReplicaId;
-pub use fs::*;
use futures::{Stream, StreamExt};
use fuzzy::CharBag;
use gpui::{
@@ -981,12 +981,11 @@ mod tests {
editor::{Editor, EditorSettings, Insert},
fs::{FakeFs, Fs as _},
people_panel::JoinWorktree,
- project::ProjectPath,
+ project::{ProjectPath, Worktree},
rpc::{self, Client, Credentials, EstablishConnectionError},
test::FakeHttpClient,
user::UserStore,
workspace::Workspace,
- worktree::Worktree,
};
#[gpui::test]
@@ -17,10 +17,10 @@ path = "src/main.rs"
test-support = [
"buffer/test-support",
"gpui/test-support",
+ "project/test-support",
+ "rpc/test-support",
"rpc_client/test-support",
"tempdir",
- "worktree/test-support",
- "rpc/test-support",
]
[dependencies]
@@ -30,11 +30,11 @@ fsevent = { path = "../fsevent" }
fuzzy = { path = "../fuzzy" }
editor = { path = "../editor" }
gpui = { path = "../gpui" }
+project = { path = "../project" }
rpc = { path = "../rpc" }
rpc_client = { path = "../rpc_client" }
sum_tree = { path = "../sum_tree" }
util = { path = "../util" }
-worktree = { path = "../worktree" }
anyhow = "1.0.38"
async-recursion = "0.3"
@@ -79,10 +79,10 @@ url = "2.2"
buffer = { path = "../buffer", features = ["test-support"] }
editor = { path = "../editor", features = ["test-support"] }
gpui = { path = "../gpui", features = ["test-support"] }
+project = { path = "../project", features = ["test-support"] }
rpc = { path = "../rpc", features = ["test-support"] }
rpc_client = { path = "../rpc_client", features = ["test-support"] }
util = { path = "../util", features = ["test-support"] }
-worktree = { path = "../worktree", features = ["test-support"] }
cargo-bundle = "0.5.0"
env_logger = "0.8"
@@ -1,10 +1,6 @@
-use crate::{
- fuzzy::PathMatch,
- project::{Project, ProjectPath},
- settings::Settings,
- workspace::Workspace,
-};
+use crate::{settings::Settings, workspace::Workspace};
use editor::{self, Editor, EditorSettings};
+use fuzzy::PathMatch;
use gpui::{
action,
elements::*,
@@ -17,6 +13,7 @@ use gpui::{
ViewContext, ViewHandle, WeakViewHandle,
};
use postage::watch;
+use project::{Project, ProjectPath};
use std::{
cmp,
path::Path,
@@ -427,9 +424,9 @@ mod tests {
use super::*;
use crate::{test::test_app_state, workspace::Workspace};
use editor::{self, Insert};
+ use project::fs::FakeFs;
use serde_json::json;
use std::path::PathBuf;
- use worktree::fs::FakeFs;
#[gpui::test]
async fn test_matching_paths(mut cx: gpui::TestAppContext) {
@@ -1,173 +0,0 @@
-use gpui::executor;
-use std::{
- cmp,
- sync::{atomic::AtomicBool, Arc},
-};
-use util;
-use worktree::{EntryKind, Snapshot};
-
-pub use fuzzy::*;
-
-pub async fn match_strings(
- candidates: &[StringMatchCandidate],
- query: &str,
- smart_case: bool,
- max_results: usize,
- cancel_flag: &AtomicBool,
- background: Arc<executor::Background>,
-) -> Vec<StringMatch> {
- let lowercase_query = query.to_lowercase().chars().collect::<Vec<_>>();
- let query = query.chars().collect::<Vec<_>>();
-
- let lowercase_query = &lowercase_query;
- let query = &query;
- let query_char_bag = CharBag::from(&lowercase_query[..]);
-
- let num_cpus = background.num_cpus().min(candidates.len());
- let segment_size = (candidates.len() + num_cpus - 1) / num_cpus;
- let mut segment_results = (0..num_cpus)
- .map(|_| Vec::with_capacity(max_results))
- .collect::<Vec<_>>();
-
- background
- .scoped(|scope| {
- for (segment_idx, results) in segment_results.iter_mut().enumerate() {
- let cancel_flag = &cancel_flag;
- scope.spawn(async move {
- let segment_start = segment_idx * segment_size;
- let segment_end = segment_start + segment_size;
- let mut matcher = Matcher::new(
- query,
- lowercase_query,
- query_char_bag,
- smart_case,
- max_results,
- );
- matcher.match_strings(
- &candidates[segment_start..segment_end],
- results,
- cancel_flag,
- );
- });
- }
- })
- .await;
-
- let mut results = Vec::new();
- for segment_result in segment_results {
- if results.is_empty() {
- results = segment_result;
- } else {
- util::extend_sorted(&mut results, segment_result, max_results, |a, b| b.cmp(&a));
- }
- }
- results
-}
-
-pub async fn match_paths(
- snapshots: &[Snapshot],
- query: &str,
- include_ignored: bool,
- smart_case: bool,
- max_results: usize,
- cancel_flag: &AtomicBool,
- background: Arc<executor::Background>,
-) -> Vec<PathMatch> {
- let path_count: usize = if include_ignored {
- snapshots.iter().map(Snapshot::file_count).sum()
- } else {
- snapshots.iter().map(Snapshot::visible_file_count).sum()
- };
- if path_count == 0 {
- return Vec::new();
- }
-
- let lowercase_query = query.to_lowercase().chars().collect::<Vec<_>>();
- let query = query.chars().collect::<Vec<_>>();
-
- let lowercase_query = &lowercase_query;
- let query = &query;
- let query_char_bag = CharBag::from(&lowercase_query[..]);
-
- let num_cpus = background.num_cpus().min(path_count);
- let segment_size = (path_count + num_cpus - 1) / num_cpus;
- let mut segment_results = (0..num_cpus)
- .map(|_| Vec::with_capacity(max_results))
- .collect::<Vec<_>>();
-
- background
- .scoped(|scope| {
- for (segment_idx, results) in segment_results.iter_mut().enumerate() {
- scope.spawn(async move {
- let segment_start = segment_idx * segment_size;
- let segment_end = segment_start + segment_size;
- let mut matcher = Matcher::new(
- query,
- lowercase_query,
- query_char_bag,
- smart_case,
- max_results,
- );
-
- let mut tree_start = 0;
- for snapshot in snapshots {
- let tree_end = if include_ignored {
- tree_start + snapshot.file_count()
- } else {
- tree_start + snapshot.visible_file_count()
- };
-
- if tree_start < segment_end && segment_start < tree_end {
- let path_prefix: Arc<str> =
- if snapshot.root_entry().map_or(false, |e| e.is_file()) {
- snapshot.root_name().into()
- } else if snapshots.len() > 1 {
- format!("{}/", snapshot.root_name()).into()
- } else {
- "".into()
- };
-
- let start = cmp::max(tree_start, segment_start) - tree_start;
- let end = cmp::min(tree_end, segment_end) - tree_start;
- let paths = snapshot
- .files(include_ignored, start)
- .take(end - start)
- .map(|entry| {
- if let EntryKind::File(char_bag) = entry.kind {
- PathMatchCandidate {
- path: &entry.path,
- char_bag,
- }
- } else {
- unreachable!()
- }
- });
-
- matcher.match_paths(
- snapshot.id(),
- path_prefix,
- paths,
- results,
- &cancel_flag,
- );
- }
- if tree_end >= segment_end {
- break;
- }
- tree_start = tree_end;
- }
- })
- }
- })
- .await;
-
- let mut results = Vec::new();
- for segment_result in segment_results {
- if results.is_empty() {
- results = segment_result;
- } else {
- util::extend_sorted(&mut results, segment_result, max_results, |a, b| b.cmp(&a));
- }
- }
- results
-}
@@ -2,12 +2,10 @@ pub mod assets;
pub mod channel;
pub mod chat_panel;
pub mod file_finder;
-mod fuzzy;
pub mod http;
pub mod language;
pub mod menus;
pub mod people_panel;
-pub mod project;
pub mod project_panel;
pub mod settings;
#[cfg(any(test, feature = "test-support"))]
@@ -24,11 +22,11 @@ pub use editor;
use gpui::{action, keymap::Binding, ModelHandle};
use parking_lot::Mutex;
use postage::watch;
+pub use project::{self, fs};
pub use rpc_client as rpc;
pub use settings::Settings;
use std::sync::Arc;
use util::TryFutureExt;
-pub use worktree::{self, fs};
action!(About);
action!(Quit);
@@ -20,12 +20,12 @@ use gpui::{
ViewContext, ViewHandle, WeakViewHandle,
};
use postage::watch;
+use project::Worktree;
use std::{
collections::{hash_map, HashMap},
ffi::OsStr,
ops::Range,
};
-use worktree::Worktree;
pub struct ProjectPanel {
project: ModelHandle<Project>,
@@ -288,7 +288,7 @@ impl ProjectPanel {
&self,
target_ix: usize,
cx: &'a AppContext,
- ) -> Option<(&'a Worktree, &'a worktree::Entry)> {
+ ) -> Option<(&'a Worktree, &'a project::Entry)> {
let project = self.project.read(cx);
let mut offset = None;
let mut ix = 0;
@@ -309,10 +309,7 @@ impl ProjectPanel {
})
}
- fn selected_entry<'a>(
- &self,
- cx: &'a AppContext,
- ) -> Option<(&'a Worktree, &'a worktree::Entry)> {
+ fn selected_entry<'a>(&self, cx: &'a AppContext) -> Option<(&'a Worktree, &'a project::Entry)> {
let selection = self.selection?;
let project = self.project.read(cx);
let worktree = project.worktree_for_id(selection.worktree_id)?.read(cx);
@@ -626,7 +623,13 @@ mod tests {
)
.await;
- let project = cx.add_model(|_| Project::new(&app_state));
+ let project = cx.add_model(|_| {
+ Project::new(
+ app_state.languages.clone(),
+ app_state.rpc.clone(),
+ app_state.fs.clone(),
+ )
+ });
let root1 = project
.update(&mut cx, |project, cx| {
project.add_local_worktree("/root1".as_ref(), cx)
@@ -12,9 +12,9 @@ use buffer::LanguageRegistry;
use futures::{future::BoxFuture, Future};
use gpui::MutableAppContext;
use parking_lot::Mutex;
+use project::fs::FakeFs;
use rpc_client as rpc;
use std::{fmt, sync::Arc};
-use worktree::fs::FakeFs;
#[cfg(test)]
#[ctor::ctor]
@@ -1,12 +1,6 @@
-use std::{cmp, sync::Arc};
-
-use crate::{
- fuzzy::{match_strings, StringMatch, StringMatchCandidate},
- settings::ThemeRegistry,
- workspace::Workspace,
- AppState, Settings,
-};
+use crate::{settings::ThemeRegistry, workspace::Workspace, AppState, Settings};
use editor::{self, Editor, EditorSettings};
+use fuzzy::{match_strings, StringMatch, StringMatchCandidate};
use gpui::{
action,
elements::*,
@@ -16,6 +10,7 @@ use gpui::{
};
use parking_lot::Mutex;
use postage::watch;
+use std::{cmp, sync::Arc};
pub struct ThemeSelector {
settings_tx: Arc<Mutex<watch::Sender<Settings>>>,
@@ -32,13 +32,13 @@ use log::error;
pub use pane::*;
pub use pane_group::*;
use postage::{prelude::Stream, watch};
+use project::Worktree;
use std::{
collections::{hash_map::Entry, HashMap},
future::Future,
path::{Path, PathBuf},
sync::Arc,
};
-use worktree::Worktree;
action!(Open, Arc<AppState>);
action!(OpenPaths, OpenParams);
@@ -376,7 +376,13 @@ pub struct Workspace {
impl Workspace {
pub fn new(app_state: &AppState, cx: &mut ViewContext<Self>) -> Self {
- let project = cx.add_model(|_| Project::new(app_state));
+ let project = cx.add_model(|_| {
+ Project::new(
+ app_state.languages.clone(),
+ app_state.rpc.clone(),
+ app_state.fs.clone(),
+ )
+ });
cx.observe(&project, |_, _, cx| cx.notify()).detach();
let pane = cx.add_view(|_| Pane::new(app_state.settings.clone()));
@@ -5,8 +5,8 @@ use buffer::{Buffer, File as _};
use editor::{Editor, EditorSettings, Event};
use gpui::{fonts::TextStyle, AppContext, ModelHandle, Task, ViewContext};
use postage::watch;
+use project::Worktree;
use std::path::Path;
-use worktree::Worktree;
impl Item for Buffer {
type View = Editor;