Cargo.lock π
@@ -907,6 +907,7 @@ dependencies = [
"fuzzy",
"gpui",
"picker",
+ "project",
"serde_json",
"settings",
"theme",
Max Brunsfeld created
This allows those actions to be bound to keystrokes in the keymap.
Also, remove the WorkspaceParams struct, simplify how Workspaces are
constructed.
Cargo.lock | 1
crates/collab/src/rpc.rs | 54 +---
crates/command_palette/Cargo.toml | 2
crates/command_palette/src/command_palette.rs | 10
crates/contacts_panel/src/contacts_panel.rs | 23 -
crates/diagnostics/src/diagnostics.rs | 45 +--
crates/editor/src/editor.rs | 4
crates/file_finder/src/file_finder.rs | 118 ++++------
crates/gpui/src/elements/uniform_list.rs | 4
crates/project/src/project.rs | 52 ++-
crates/project_panel/src/project_panel.rs | 19 +
crates/project_symbols/src/project_symbols.rs | 2
crates/search/src/project_search.rs | 2
crates/theme_selector/src/theme_selector.rs | 18 +
crates/vim/src/vim_test_context.rs | 11
crates/workspace/src/pane.rs | 12
crates/workspace/src/workspace.rs | 143 ++++--------
crates/zed/src/main.rs | 17
crates/zed/src/menus.rs | 8
crates/zed/src/test.rs | 39 ---
crates/zed/src/zed.rs | 237 +++++++++-----------
21 files changed, 335 insertions(+), 486 deletions(-)
@@ -907,6 +907,7 @@ dependencies = [
"fuzzy",
"gpui",
"picker",
+ "project",
"serde_json",
"settings",
"theme",
@@ -1630,7 +1630,7 @@ mod tests {
use gpui::{
executor::{self, Deterministic},
geometry::vector::vec2f,
- ModelHandle, TestAppContext, ViewHandle,
+ ModelHandle, Task, TestAppContext, ViewHandle,
};
use language::{
range_to_lsp, tree_sitter_rust, Diagnostic, DiagnosticEntry, FakeLspAdapter, Language,
@@ -1662,7 +1662,7 @@ mod tests {
time::Duration,
};
use theme::ThemeRegistry;
- use workspace::{Item, SplitDirection, ToggleFollow, Workspace, WorkspaceParams};
+ use workspace::{Item, SplitDirection, ToggleFollow, Workspace};
#[cfg(test)]
#[ctor::ctor]
@@ -4322,13 +4322,7 @@ mod tests {
// Join the project as client B.
let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await;
- let mut params = cx_b.update(WorkspaceParams::test);
- params.languages = lang_registry.clone();
- params.project = project_b.clone();
- params.client = client_b.client.clone();
- params.user_store = client_b.user_store.clone();
-
- let (_window_b, workspace_b) = cx_b.add_window(|cx| Workspace::new(¶ms, cx));
+ let (_window_b, workspace_b) = cx_b.add_window(|cx| Workspace::new(project_b.clone(), cx));
let editor_b = workspace_b
.update(cx_b, |workspace, cx| {
workspace.open_path((worktree_id, "main.rs"), true, cx)
@@ -4563,13 +4557,7 @@ mod tests {
// Join the worktree as client B.
let project_b = client_b.build_remote_project(&project_a, cx_a, cx_b).await;
- let mut params = cx_b.update(WorkspaceParams::test);
- params.languages = lang_registry.clone();
- params.project = project_b.clone();
- params.client = client_b.client.clone();
- params.user_store = client_b.user_store.clone();
-
- let (_window_b, workspace_b) = cx_b.add_window(|cx| Workspace::new(¶ms, cx));
+ let (_window_b, workspace_b) = cx_b.add_window(|cx| Workspace::new(project_b.clone(), cx));
let editor_b = workspace_b
.update(cx_b, |workspace, cx| {
workspace.open_path((worktree_id, "one.rs"), true, cx)
@@ -6602,13 +6590,21 @@ mod tests {
})
});
+ let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http, cx));
+ let app_state = Arc::new(workspace::AppState {
+ client: client.clone(),
+ user_store: user_store.clone(),
+ languages: Arc::new(LanguageRegistry::new(Task::ready(()))),
+ themes: ThemeRegistry::new((), cx.font_cache()),
+ fs: FakeFs::new(cx.background()),
+ build_window_options: || Default::default(),
+ build_workspace: |_, _, _| unimplemented!(),
+ });
+
Channel::init(&client);
Project::init(&client);
- cx.update(|cx| {
- workspace::init(&client, cx);
- });
+ cx.update(|cx| workspace::init(app_state.clone(), cx));
- let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http, cx));
client
.authenticate_and_connect(false, &cx.to_async())
.await
@@ -6846,23 +6842,7 @@ mod tests {
cx: &mut TestAppContext,
) -> ViewHandle<Workspace> {
let (window_id, _) = cx.add_window(|_| EmptyView);
- cx.add_view(window_id, |cx| {
- let fs = project.read(cx).fs().clone();
- Workspace::new(
- &WorkspaceParams {
- fs,
- project: project.clone(),
- user_store: self.user_store.clone(),
- languages: self.language_registry.clone(),
- themes: ThemeRegistry::new((), cx.font_cache().clone()),
- channel_list: cx.add_model(|cx| {
- ChannelList::new(self.user_store.clone(), self.client.clone(), cx)
- }),
- client: self.client.clone(),
- },
- cx,
- )
- })
+ cx.add_view(window_id, |cx| Workspace::new(project.clone(), cx))
}
async fn simulate_host(
@@ -12,6 +12,7 @@ editor = { path = "../editor" }
fuzzy = { path = "../fuzzy" }
gpui = { path = "../gpui" }
picker = { path = "../picker" }
+project = { path = "../project" }
settings = { path = "../settings" }
util = { path = "../util" }
theme = { path = "../theme" }
@@ -20,6 +21,7 @@ workspace = { path = "../workspace" }
[dev-dependencies]
gpui = { path = "../gpui", features = ["test-support"] }
editor = { path = "../editor", features = ["test-support"] }
+project = { path = "../project", features = ["test-support"] }
serde_json = { version = "1.0.64", features = ["preserve_order"] }
workspace = { path = "../workspace", features = ["test-support"] }
ctor = "0.1"
@@ -299,7 +299,8 @@ mod tests {
use super::*;
use editor::Editor;
use gpui::TestAppContext;
- use workspace::{Workspace, WorkspaceParams};
+ use project::Project;
+ use workspace::{AppState, Workspace};
#[test]
fn test_humanize_action_name() {
@@ -319,15 +320,16 @@ mod tests {
#[gpui::test]
async fn test_command_palette(cx: &mut TestAppContext) {
- let params = cx.update(WorkspaceParams::test);
+ let app_state = cx.update(AppState::test);
cx.update(|cx| {
editor::init(cx);
- workspace::init(¶ms.client, cx);
+ workspace::init(app_state.clone(), cx);
init(cx);
});
- let (window_id, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
+ let project = Project::test(app_state.fs.clone(), [], cx).await;
+ let (window_id, workspace) = cx.add_window(|cx| Workspace::new(project, cx));
let editor = cx.add_view(window_id, |cx| {
let mut editor = Editor::single_line(None, cx);
editor.set_text("abc", cx);
@@ -60,7 +60,6 @@ pub struct ContactsPanel {
filter_editor: ViewHandle<Editor>,
collapsed_sections: Vec<Section>,
selection: Option<usize>,
- app_state: Arc<AppState>,
_maintain_contacts: Subscription,
}
@@ -175,7 +174,6 @@ impl ContactsPanel {
let mut this = Self {
list_state: ListState::new(0, Orientation::Top, 1000., {
let this = cx.weak_handle();
- let app_state = app_state.clone();
move |ix, cx| {
let this = this.upgrade(cx).unwrap();
let this = this.read(cx);
@@ -222,7 +220,6 @@ impl ContactsPanel {
contact.clone(),
current_user_id,
*project_ix,
- app_state.clone(),
theme,
is_last_project_for_contact,
is_selected,
@@ -240,7 +237,6 @@ impl ContactsPanel {
_maintain_contacts: cx
.observe(&app_state.user_store, |this, _, cx| this.update_entries(cx)),
user_store: app_state.user_store.clone(),
- app_state,
};
this.update_entries(cx);
this
@@ -339,7 +335,6 @@ impl ContactsPanel {
contact: Arc<Contact>,
current_user_id: Option<u64>,
project_index: usize,
- app_state: Arc<AppState>,
theme: &theme::ContactsPanel,
is_last_project: bool,
is_selected: bool,
@@ -444,7 +439,6 @@ impl ContactsPanel {
cx.dispatch_global_action(JoinProject {
contact: contact.clone(),
project_index,
- app_state: app_state.clone(),
});
}
})
@@ -770,7 +764,6 @@ impl ContactsPanel {
.dispatch_global_action(JoinProject {
contact: contact.clone(),
project_index: *project_index,
- app_state: self.app_state.clone(),
}),
_ => {}
}
@@ -916,17 +909,17 @@ impl PartialEq for ContactEntry {
#[cfg(test)]
mod tests {
use super::*;
- use client::{proto, test::FakeServer, ChannelList, Client};
+ use client::{proto, test::FakeServer, Client};
use gpui::TestAppContext;
use language::LanguageRegistry;
+ use project::Project;
use theme::ThemeRegistry;
- use workspace::WorkspaceParams;
#[gpui::test]
async fn test_contact_panel(cx: &mut TestAppContext) {
let (app_state, server) = init(cx).await;
- let workspace_params = cx.update(WorkspaceParams::test);
- let workspace = cx.add_view(0, |cx| Workspace::new(&workspace_params, cx));
+ let project = Project::test(app_state.fs.clone(), [], cx).await;
+ let workspace = cx.add_view(0, |cx| Workspace::new(project, cx));
let panel = cx.add_view(0, |cx| {
ContactsPanel::new(app_state.clone(), workspace.downgrade(), cx)
});
@@ -1110,13 +1103,6 @@ mod tests {
let mut client = Client::new(http_client.clone());
let server = FakeServer::for_client(100, &mut client, &cx).await;
let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http_client, cx));
- let channel_list =
- cx.add_model(|cx| ChannelList::new(user_store.clone(), client.clone(), cx));
-
- let get_channels = server.receive::<proto::GetChannels>().await.unwrap();
- server
- .respond(get_channels.receipt(), Default::default())
- .await;
(
Arc::new(AppState {
@@ -1125,7 +1111,6 @@ mod tests {
client,
user_store: user_store.clone(),
fs,
- channel_list,
build_window_options: || unimplemented!(),
build_workspace: |_, _, _| unimplemented!(),
}),
@@ -707,49 +707,42 @@ mod tests {
use language::{Diagnostic, DiagnosticEntry, DiagnosticSeverity, PointUtf16};
use serde_json::json;
use unindent::Unindent as _;
- use workspace::WorkspaceParams;
+ use workspace::AppState;
#[gpui::test]
async fn test_diagnostics(cx: &mut TestAppContext) {
- let params = cx.update(WorkspaceParams::test);
- let project = params.project.clone();
- let workspace = cx.add_view(0, |cx| Workspace::new(¶ms, cx));
-
- params
+ let app_state = cx.update(AppState::test);
+ app_state
.fs
.as_fake()
.insert_tree(
"/test",
json!({
"consts.rs": "
- const a: i32 = 'a';
- const b: i32 = c;
- "
+ const a: i32 = 'a';
+ const b: i32 = c;
+ "
.unindent(),
"main.rs": "
- fn main() {
- let x = vec![];
- let y = vec![];
- a(x);
- b(y);
- // comment 1
- // comment 2
- c(y);
- d(x);
- }
- "
+ fn main() {
+ let x = vec![];
+ let y = vec![];
+ a(x);
+ b(y);
+ // comment 1
+ // comment 2
+ c(y);
+ d(x);
+ }
+ "
.unindent(),
}),
)
.await;
- project
- .update(cx, |project, cx| {
- project.find_or_create_local_worktree("/test", true, cx)
- })
- .await
- .unwrap();
+ let project = Project::test(app_state.fs.clone(), ["/test".as_ref()], cx).await;
+ let workspace = cx.add_view(0, |cx| Workspace::new(project.clone(), cx));
// Create some diagnostics
project.update(cx, |project, cx| {
@@ -8815,7 +8815,7 @@ mod tests {
let fs = FakeFs::new(cx.background().clone());
fs.insert_file("/file.rs", Default::default()).await;
- let project = Project::test(fs, ["/file.rs"], cx).await;
+ let project = Project::test(fs, ["/file.rs".as_ref()], cx).await;
project.update(cx, |project, _| project.languages().add(Arc::new(language)));
let buffer = project
.update(cx, |project, cx| project.open_local_buffer("/file.rs", cx))
@@ -8937,7 +8937,7 @@ mod tests {
let fs = FakeFs::new(cx.background().clone());
fs.insert_file("/file.rs", text).await;
- let project = Project::test(fs, ["/file.rs"], cx).await;
+ let project = Project::test(fs, ["/file.rs".as_ref()], cx).await;
project.update(cx, |project, _| project.languages().add(Arc::new(language)));
let buffer = project
.update(cx, |project, cx| project.open_local_buffer("/file.rs", cx))
@@ -258,9 +258,10 @@ mod tests {
use super::*;
use editor::{Editor, Input};
use serde_json::json;
- use std::path::PathBuf;
- use workspace::menu::{Confirm, SelectNext};
- use workspace::{Workspace, WorkspaceParams};
+ use workspace::{
+ menu::{Confirm, SelectNext},
+ AppState, Workspace,
+ };
#[ctor::ctor]
fn init_logger() {
@@ -271,13 +272,13 @@ mod tests {
#[gpui::test]
async fn test_matching_paths(cx: &mut gpui::TestAppContext) {
- cx.update(|cx| {
+ let app_state = cx.update(|cx| {
super::init(cx);
editor::init(cx);
+ AppState::test(cx)
});
- let params = cx.update(WorkspaceParams::test);
- params
+ app_state
.fs
.as_fake()
.insert_tree(
@@ -291,16 +292,8 @@ mod tests {
)
.await;
- let (window_id, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
- params
- .project
- .update(cx, |project, cx| {
- project.find_or_create_local_worktree("/root", true, cx)
- })
- .await
- .unwrap();
- cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx))
- .await;
+ let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
+ let (window_id, workspace) = cx.add_window(|cx| Workspace::new(project, cx));
cx.dispatch_action(window_id, Toggle);
let finder = cx.read(|cx| {
@@ -341,32 +334,26 @@ mod tests {
#[gpui::test]
async fn test_matching_cancellation(cx: &mut gpui::TestAppContext) {
- let params = cx.update(WorkspaceParams::test);
- let fs = params.fs.as_fake();
- fs.insert_tree(
- "/dir",
- json!({
- "hello": "",
- "goodbye": "",
- "halogen-light": "",
- "happiness": "",
- "height": "",
- "hi": "",
- "hiccup": "",
- }),
- )
- .await;
-
- let (_, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
- params
- .project
- .update(cx, |project, cx| {
- project.find_or_create_local_worktree("/dir", true, cx)
- })
- .await
- .unwrap();
- cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx))
+ let app_state = cx.update(AppState::test);
+ app_state
+ .fs
+ .as_fake()
+ .insert_tree(
+ "/dir",
+ json!({
+ "hello": "",
+ "goodbye": "",
+ "halogen-light": "",
+ "happiness": "",
+ "height": "",
+ "hi": "",
+ "hiccup": "",
+ }),
+ )
.await;
+
+ let project = Project::test(app_state.fs.clone(), ["/dir".as_ref()], cx).await;
+ let (_, workspace) = cx.add_window(|cx| Workspace::new(project, cx));
let (_, finder) =
cx.add_window(|cx| FileFinder::new(workspace.read(cx).project().clone(), cx));
@@ -406,23 +393,20 @@ mod tests {
#[gpui::test]
async fn test_single_file_worktrees(cx: &mut gpui::TestAppContext) {
- let params = cx.update(WorkspaceParams::test);
- params
+ let app_state = cx.update(AppState::test);
+ app_state
.fs
.as_fake()
.insert_tree("/root", json!({ "the-parent-dir": { "the-file": "" } }))
.await;
- let (_, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
- params
- .project
- .update(cx, |project, cx| {
- project.find_or_create_local_worktree("/root/the-parent-dir/the-file", true, cx)
- })
- .await
- .unwrap();
- cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx))
- .await;
+ let project = Project::test(
+ app_state.fs.clone(),
+ ["/root/the-parent-dir/the-file".as_ref()],
+ cx,
+ )
+ .await;
+ let (_, workspace) = cx.add_window(|cx| Workspace::new(project, cx));
let (_, finder) =
cx.add_window(|cx| FileFinder::new(workspace.read(cx).project().clone(), cx));
@@ -451,10 +435,12 @@ mod tests {
finder.read_with(cx, |f, _| assert_eq!(f.matches.len(), 0));
}
- #[gpui::test(retries = 5)]
+ #[gpui::test]
async fn test_multiple_matches_with_same_relative_path(cx: &mut gpui::TestAppContext) {
- let params = cx.update(WorkspaceParams::test);
- params
+ cx.foreground().forbid_parking();
+
+ let app_state = cx.update(AppState::test);
+ app_state
.fs
.as_fake()
.insert_tree(
@@ -466,19 +452,13 @@ mod tests {
)
.await;
- let (_, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
-
- workspace
- .update(cx, |workspace, cx| {
- workspace.open_paths(
- vec![PathBuf::from("/root/dir1"), PathBuf::from("/root/dir2")],
- cx,
- )
- })
- .await;
- cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx))
- .await;
-
+ let project = Project::test(
+ app_state.fs.clone(),
+ ["/root/dir1".as_ref(), "/root/dir2".as_ref()],
+ cx,
+ )
+ .await;
+ let (_, workspace) = cx.add_window(|cx| Workspace::new(project, cx));
let (_, finder) =
cx.add_window(|cx| FileFinder::new(workspace.read(cx).project().clone(), cx));
@@ -215,12 +215,12 @@ where
self.autoscroll(scroll_max, size.y(), item_height);
let start = cmp::min(
- ((self.scroll_top() - self.padding_top) / item_height) as usize,
+ ((self.scroll_top() - self.padding_top) / item_height.max(1.)) as usize,
self.item_count,
);
let end = cmp::min(
self.item_count,
- start + (size.y() / item_height).ceil() as usize + 1,
+ start + (size.y() / item_height.max(1.)).ceil() as usize + 1,
);
if (start..end).contains(&sample_item_ix) {
@@ -497,7 +497,7 @@ impl Project {
#[cfg(any(test, feature = "test-support"))]
pub async fn test(
fs: Arc<dyn Fs>,
- root_paths: impl IntoIterator<Item = impl AsRef<Path>>,
+ root_paths: impl IntoIterator<Item = &Path>,
cx: &mut gpui::TestAppContext,
) -> ModelHandle<Project> {
let languages = Arc::new(LanguageRegistry::test());
@@ -528,6 +528,14 @@ impl Project {
&self.languages
}
+ pub fn client(&self) -> Arc<Client> {
+ self.client.clone()
+ }
+
+ pub fn user_store(&self) -> ModelHandle<UserStore> {
+ self.user_store.clone()
+ }
+
#[cfg(any(test, feature = "test-support"))]
pub fn check_invariants(&self, cx: &AppContext) {
if self.is_local() {
@@ -5294,7 +5302,7 @@ mod tests {
)
.unwrap();
- let project = Project::test(Arc::new(RealFs), [root_link_path], cx).await;
+ let project = Project::test(Arc::new(RealFs), [root_link_path.as_ref()], cx).await;
project.read_with(cx, |project, cx| {
let tree = project.worktrees(cx).next().unwrap().read(cx);
@@ -5378,7 +5386,7 @@ mod tests {
)
.await;
- let project = Project::test(fs.clone(), ["/the-root"], cx).await;
+ let project = Project::test(fs.clone(), ["/the-root".as_ref()], cx).await;
project.update(cx, |project, _| {
project.languages.add(Arc::new(rust_language));
project.languages.add(Arc::new(json_language));
@@ -5714,7 +5722,7 @@ mod tests {
)
.await;
- let project = Project::test(fs, ["/dir/a.rs", "/dir/b.rs"], cx).await;
+ let project = Project::test(fs, ["/dir/a.rs".as_ref(), "/dir/b.rs".as_ref()], cx).await;
let buffer_a = project
.update(cx, |project, cx| project.open_local_buffer("/dir/a.rs", cx))
@@ -5825,7 +5833,7 @@ mod tests {
)
.await;
- let project = Project::test(fs, ["/dir"], cx).await;
+ let project = Project::test(fs, ["/dir".as_ref()], cx).await;
project.update(cx, |project, _| project.languages.add(Arc::new(language)));
let worktree_id =
project.read_with(cx, |p, cx| p.worktrees(cx).next().unwrap().read(cx).id());
@@ -5947,7 +5955,7 @@ mod tests {
let fs = FakeFs::new(cx.background());
fs.insert_tree("/dir", json!({ "a.rs": "" })).await;
- let project = Project::test(fs, ["/dir"], cx).await;
+ let project = Project::test(fs, ["/dir".as_ref()], cx).await;
project.update(cx, |project, _| project.languages.add(Arc::new(language)));
let buffer = project
@@ -6016,7 +6024,7 @@ mod tests {
let fs = FakeFs::new(cx.background());
fs.insert_tree("/dir", json!({ "a.rs": text })).await;
- let project = Project::test(fs, ["/dir"], cx).await;
+ let project = Project::test(fs, ["/dir".as_ref()], cx).await;
project.update(cx, |project, _| project.languages.add(Arc::new(language)));
let buffer = project
@@ -6285,7 +6293,7 @@ mod tests {
let fs = FakeFs::new(cx.background());
fs.insert_tree("/dir", json!({ "a.rs": text })).await;
- let project = Project::test(fs, ["/dir"], cx).await;
+ let project = Project::test(fs, ["/dir".as_ref()], cx).await;
let buffer = project
.update(cx, |project, cx| project.open_local_buffer("/dir/a.rs", cx))
.await
@@ -6376,7 +6384,7 @@ mod tests {
)
.await;
- let project = Project::test(fs, ["/dir"], cx).await;
+ let project = Project::test(fs, ["/dir".as_ref()], cx).await;
project.update(cx, |project, _| project.languages.add(Arc::new(language)));
let buffer = project
.update(cx, |project, cx| project.open_local_buffer("/dir/a.rs", cx))
@@ -6530,7 +6538,7 @@ mod tests {
)
.await;
- let project = Project::test(fs, ["/dir"], cx).await;
+ let project = Project::test(fs, ["/dir".as_ref()], cx).await;
let buffer = project
.update(cx, |project, cx| project.open_local_buffer("/dir/a.rs", cx))
.await
@@ -6686,7 +6694,7 @@ mod tests {
)
.await;
- let project = Project::test(fs, ["/dir/b.rs"], cx).await;
+ let project = Project::test(fs, ["/dir/b.rs".as_ref()], cx).await;
project.update(cx, |project, _| project.languages.add(Arc::new(language)));
let buffer = project
@@ -6780,7 +6788,7 @@ mod tests {
)
.await;
- let project = Project::test(fs, ["/dir"], cx).await;
+ let project = Project::test(fs, ["/dir".as_ref()], cx).await;
project.update(cx, |project, _| project.languages.add(Arc::new(language)));
let buffer = project
.update(cx, |p, cx| p.open_local_buffer("/dir/a.ts", cx))
@@ -6838,7 +6846,7 @@ mod tests {
)
.await;
- let project = Project::test(fs, ["/dir"], cx).await;
+ let project = Project::test(fs, ["/dir".as_ref()], cx).await;
project.update(cx, |project, _| project.languages.add(Arc::new(language)));
let buffer = project
.update(cx, |p, cx| p.open_local_buffer("/dir/a.ts", cx))
@@ -6944,7 +6952,7 @@ mod tests {
)
.await;
- let project = Project::test(fs.clone(), ["/dir"], cx).await;
+ let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await;
let buffer = project
.update(cx, |p, cx| p.open_local_buffer("/dir/file1", cx))
.await
@@ -6973,7 +6981,7 @@ mod tests {
)
.await;
- let project = Project::test(fs.clone(), ["/dir/file1"], cx).await;
+ let project = Project::test(fs.clone(), ["/dir/file1".as_ref()], cx).await;
let buffer = project
.update(cx, |p, cx| p.open_local_buffer("/dir/file1", cx))
.await
@@ -6995,7 +7003,7 @@ mod tests {
let fs = FakeFs::new(cx.background());
fs.insert_tree("/dir", json!({})).await;
- let project = Project::test(fs.clone(), ["/dir"], cx).await;
+ let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await;
let buffer = project.update(cx, |project, cx| {
project.create_buffer("", None, cx).unwrap()
});
@@ -7182,7 +7190,7 @@ mod tests {
)
.await;
- let project = Project::test(fs.clone(), ["/dir"], cx).await;
+ let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await;
// Spawn multiple tasks to open paths, repeating some paths.
let (buffer_a_1, buffer_b, buffer_a_2) = project.update(cx, |p, cx| {
@@ -7227,7 +7235,7 @@ mod tests {
)
.await;
- let project = Project::test(fs.clone(), ["/dir"], cx).await;
+ let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await;
let buffer1 = project
.update(cx, |p, cx| p.open_local_buffer("/dir/file1", cx))
@@ -7359,7 +7367,7 @@ mod tests {
}),
)
.await;
- let project = Project::test(fs.clone(), ["/dir"], cx).await;
+ let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await;
let buffer = project
.update(cx, |p, cx| p.open_local_buffer("/dir/the-file", cx))
.await
@@ -7444,7 +7452,7 @@ mod tests {
)
.await;
- let project = Project::test(fs.clone(), ["/the-dir"], cx).await;
+ let project = Project::test(fs.clone(), ["/the-dir".as_ref()], cx).await;
let buffer = project
.update(cx, |p, cx| p.open_local_buffer("/the-dir/a.rs", cx))
.await
@@ -7708,7 +7716,7 @@ mod tests {
)
.await;
- let project = Project::test(fs.clone(), ["/dir"], cx).await;
+ let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await;
project.update(cx, |project, _| project.languages.add(Arc::new(language)));
let buffer = project
.update(cx, |project, cx| {
@@ -7827,7 +7835,7 @@ mod tests {
}),
)
.await;
- let project = Project::test(fs.clone(), ["/dir"], cx).await;
+ let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await;
assert_eq!(
search(&project, SearchQuery::text("TWO", false, true), cx)
.await
@@ -913,11 +913,14 @@ mod tests {
use project::FakeFs;
use serde_json::json;
use std::{collections::HashSet, path::Path};
- use workspace::WorkspaceParams;
#[gpui::test]
async fn test_visible_list(cx: &mut gpui::TestAppContext) {
cx.foreground().forbid_parking();
+ cx.update(|cx| {
+ let settings = Settings::test(cx);
+ cx.set_global(settings);
+ });
let fs = FakeFs::new(cx.background());
fs.insert_tree(
@@ -956,9 +959,8 @@ mod tests {
)
.await;
- let project = Project::test(fs.clone(), ["/root1", "/root2"], cx).await;
- let params = cx.update(WorkspaceParams::test);
- let (_, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
+ let project = Project::test(fs.clone(), ["/root1".as_ref(), "/root2".as_ref()], cx).await;
+ let (_, workspace) = cx.add_window(|cx| Workspace::new(project.clone(), cx));
let panel = workspace.update(cx, |_, cx| ProjectPanel::new(project, cx));
assert_eq!(
visible_entries_as_strings(&panel, 0..50, cx),
@@ -1005,6 +1007,10 @@ mod tests {
#[gpui::test(iterations = 30)]
async fn test_editing_files(cx: &mut gpui::TestAppContext) {
cx.foreground().forbid_parking();
+ cx.update(|cx| {
+ let settings = Settings::test(cx);
+ cx.set_global(settings);
+ });
let fs = FakeFs::new(cx.background());
fs.insert_tree(
@@ -1043,9 +1049,8 @@ mod tests {
)
.await;
- let project = Project::test(fs.clone(), ["/root1", "/root2"], cx).await;
- let params = cx.update(WorkspaceParams::test);
- let (_, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
+ let project = Project::test(fs.clone(), ["/root1".as_ref(), "/root2".as_ref()], cx).await;
+ let (_, workspace) = cx.add_window(|cx| Workspace::new(project.clone(), cx));
let panel = workspace.update(cx, |_, cx| ProjectPanel::new(project, cx));
select_path(&panel, "root1", cx);
@@ -295,7 +295,7 @@ mod tests {
let fs = FakeFs::new(cx.background());
fs.insert_tree("/dir", json!({ "test.rs": "" })).await;
- let project = Project::test(fs.clone(), ["/dir"], cx).await;
+ let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await;
project.update(cx, |project, _| project.languages().add(Arc::new(language)));
let _buffer = project
@@ -848,7 +848,7 @@ mod tests {
}),
)
.await;
- let project = Project::test(fs.clone(), ["/dir"], cx).await;
+ let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await;
let search = cx.add_model(|cx| ProjectSearch::new(project, cx));
let search_view = cx.add_view(Default::default(), |cx| {
ProjectSearchView::new(search.clone(), cx)
@@ -7,7 +7,7 @@ use picker::{Picker, PickerDelegate};
use settings::Settings;
use std::sync::Arc;
use theme::{Theme, ThemeRegistry};
-use workspace::Workspace;
+use workspace::{AppState, Workspace};
pub struct ThemeSelector {
registry: Arc<ThemeRegistry>,
@@ -21,9 +21,14 @@ pub struct ThemeSelector {
actions!(theme_selector, [Toggle, Reload]);
-pub fn init(cx: &mut MutableAppContext) {
- cx.add_action(ThemeSelector::toggle);
+pub fn init(app_state: Arc<AppState>, cx: &mut MutableAppContext) {
Picker::<ThemeSelector>::init(cx);
+ cx.add_action({
+ let theme_registry = app_state.themes.clone();
+ move |workspace, _: &Toggle, cx| {
+ ThemeSelector::toggle(workspace, theme_registry.clone(), cx)
+ }
+ });
}
pub enum Event {
@@ -63,8 +68,11 @@ impl ThemeSelector {
this
}
- fn toggle(workspace: &mut Workspace, _: &Toggle, cx: &mut ViewContext<Workspace>) {
- let themes = workspace.themes();
+ fn toggle(
+ workspace: &mut Workspace,
+ themes: Arc<ThemeRegistry>,
+ cx: &mut ViewContext<Workspace>,
+ ) {
workspace.toggle_modal(cx, |_, cx| {
let this = cx.add_view(|cx| Self::new(themes, cx));
cx.subscribe(&this, Self::on_event).detach();
@@ -7,11 +7,12 @@ use editor::{display_map::ToDisplayPoint, Autoscroll};
use gpui::{json::json, keymap::Keystroke, ViewHandle};
use indoc::indoc;
use language::Selection;
+use project::Project;
use util::{
set_eq,
test::{marked_text, marked_text_ranges_by, SetEqError},
};
-use workspace::{WorkspaceHandle, WorkspaceParams};
+use workspace::{AppState, WorkspaceHandle};
use crate::{state::Operator, *};
@@ -30,7 +31,8 @@ impl<'a> VimTestContext<'a> {
settings::KeymapFileContent::load("keymaps/vim.json", cx).unwrap();
});
- let params = cx.update(WorkspaceParams::test);
+ let params = cx.update(AppState::test);
+ let project = Project::test(params.fs.clone(), [], cx).await;
cx.update(|cx| {
cx.update_global(|settings: &mut Settings, _| {
@@ -44,9 +46,8 @@ impl<'a> VimTestContext<'a> {
.insert_tree("/root", json!({ "dir": { "test.txt": "" } }))
.await;
- let (window_id, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
- params
- .project
+ let (window_id, workspace) = cx.add_window(|cx| Workspace::new(project.clone(), cx));
+ project
.update(cx, |project, cx| {
project.find_or_create_local_worktree("/root", true, cx)
})
@@ -920,7 +920,7 @@ impl NavHistory {
#[cfg(test)]
mod tests {
use super::*;
- use crate::WorkspaceParams;
+ use crate::AppState;
use gpui::{ModelHandle, TestAppContext, ViewContext};
use project::Project;
use std::sync::atomic::AtomicUsize;
@@ -929,8 +929,9 @@ mod tests {
async fn test_close_items(cx: &mut TestAppContext) {
cx.foreground().forbid_parking();
- let params = cx.update(WorkspaceParams::test);
- let (window_id, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
+ let app_state = cx.update(AppState::test);
+ let project = Project::test(app_state.fs.clone(), None, cx).await;
+ let (window_id, workspace) = cx.add_window(|cx| Workspace::new(project, cx));
let item1 = cx.add_view(window_id, |_| {
let mut item = TestItem::new();
item.is_dirty = true;
@@ -1019,8 +1020,9 @@ mod tests {
async fn test_prompting_only_on_last_item_for_entry(cx: &mut TestAppContext) {
cx.foreground().forbid_parking();
- let params = cx.update(WorkspaceParams::test);
- let (window_id, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
+ let app_state = cx.update(AppState::test);
+ let project = Project::test(app_state.fs.clone(), [], cx).await;
+ let (window_id, workspace) = cx.add_window(|cx| Workspace::new(project, cx));
let item = cx.add_view(window_id, |_| {
let mut item = TestItem::new();
item.is_dirty = true;
@@ -9,8 +9,7 @@ mod waiting_room;
use anyhow::{anyhow, Context, Result};
use client::{
- proto, Authenticate, ChannelList, Client, Contact, PeerId, Subscription, TypedEnvelope, User,
- UserStore,
+ proto, Authenticate, Client, Contact, PeerId, Subscription, TypedEnvelope, User, UserStore,
};
use clock::ReplicaId;
use collections::{hash_map, HashMap, HashSet};
@@ -75,6 +74,8 @@ type FollowableItemBuilders = HashMap<
actions!(
workspace,
[
+ Open,
+ OpenNew,
Unfollow,
Save,
ActivatePreviousPane,
@@ -83,16 +84,9 @@ actions!(
]
);
-#[derive(Clone)]
-pub struct Open(pub Arc<AppState>);
-
-#[derive(Clone)]
-pub struct OpenNew(pub Arc<AppState>);
-
#[derive(Clone)]
pub struct OpenPaths {
pub paths: Vec<PathBuf>,
- pub app_state: Arc<AppState>,
}
#[derive(Clone)]
@@ -102,31 +96,37 @@ pub struct ToggleFollow(pub PeerId);
pub struct JoinProject {
pub contact: Arc<Contact>,
pub project_index: usize,
- pub app_state: Arc<AppState>,
}
-impl_internal_actions!(
- workspace,
- [Open, OpenNew, OpenPaths, ToggleFollow, JoinProject]
-);
+impl_internal_actions!(workspace, [OpenPaths, ToggleFollow, JoinProject]);
-pub fn init(client: &Arc<Client>, cx: &mut MutableAppContext) {
+pub fn init(app_state: Arc<AppState>, cx: &mut MutableAppContext) {
pane::init(cx);
cx.add_global_action(open);
- cx.add_global_action(move |action: &OpenPaths, cx: &mut MutableAppContext| {
- open_paths(&action.paths, &action.app_state, cx).detach();
+ cx.add_global_action({
+ let app_state = Arc::downgrade(&app_state);
+ move |action: &OpenPaths, cx: &mut MutableAppContext| {
+ if let Some(app_state) = app_state.upgrade() {
+ open_paths(&action.paths, &app_state, cx).detach();
+ }
+ }
});
- cx.add_global_action(move |action: &OpenNew, cx: &mut MutableAppContext| {
- open_new(&action.0, cx)
+ cx.add_global_action({
+ let app_state = Arc::downgrade(&app_state);
+ move |_: &OpenNew, cx: &mut MutableAppContext| {
+ if let Some(app_state) = app_state.upgrade() {
+ open_new(&app_state, cx)
+ }
+ }
});
- cx.add_global_action(move |action: &JoinProject, cx: &mut MutableAppContext| {
- join_project(
- action.contact.clone(),
- action.project_index,
- &action.app_state,
- cx,
- );
+ cx.add_global_action({
+ let app_state = Arc::downgrade(&app_state);
+ move |action: &JoinProject, cx: &mut MutableAppContext| {
+ if let Some(app_state) = app_state.upgrade() {
+ join_project(action.contact.clone(), action.project_index, &app_state, cx);
+ }
+ }
});
cx.add_async_action(Workspace::toggle_follow);
@@ -151,6 +151,7 @@ pub fn init(client: &Arc<Client>, cx: &mut MutableAppContext) {
workspace.activate_next_pane(cx)
});
+ let client = &app_state.client;
client.add_view_request_handler(Workspace::handle_follow);
client.add_view_message_handler(Workspace::handle_unfollow);
client.add_view_message_handler(Workspace::handle_update_followers);
@@ -188,7 +189,6 @@ pub struct AppState {
pub client: Arc<client::Client>,
pub user_store: ModelHandle<client::UserStore>,
pub fs: Arc<dyn fs::Fs>,
- pub channel_list: ModelHandle<client::ChannelList>,
pub build_window_options: fn() -> WindowOptions<'static>,
pub build_workspace:
fn(ModelHandle<Project>, &Arc<AppState>, &mut ViewContext<Workspace>) -> Workspace,
@@ -636,20 +636,9 @@ impl Into<AnyViewHandle> for &dyn NotificationHandle {
}
}
-#[derive(Clone)]
-pub struct WorkspaceParams {
- pub project: ModelHandle<Project>,
- pub client: Arc<Client>,
- pub fs: Arc<dyn Fs>,
- pub languages: Arc<LanguageRegistry>,
- pub themes: Arc<ThemeRegistry>,
- pub user_store: ModelHandle<UserStore>,
- pub channel_list: ModelHandle<ChannelList>,
-}
-
-impl WorkspaceParams {
+impl AppState {
#[cfg(any(test, feature = "test-support"))]
- pub fn test(cx: &mut MutableAppContext) -> Self {
+ pub fn test(cx: &mut MutableAppContext) -> Arc<Self> {
let settings = Settings::test(cx);
cx.set_global(settings);
@@ -658,42 +647,16 @@ impl WorkspaceParams {
let http_client = client::test::FakeHttpClient::with_404_response();
let client = Client::new(http_client.clone());
let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http_client, cx));
- let project = Project::local(
- client.clone(),
- user_store.clone(),
- languages.clone(),
- fs.clone(),
- cx,
- );
- Self {
- project,
- channel_list: cx
- .add_model(|cx| ChannelList::new(user_store.clone(), client.clone(), cx)),
+ let themes = ThemeRegistry::new((), cx.font_cache().clone());
+ Arc::new(Self {
client,
- themes: ThemeRegistry::new((), cx.font_cache().clone()),
+ themes,
fs,
languages,
user_store,
- }
- }
-
- #[cfg(any(test, feature = "test-support"))]
- pub fn local(app_state: &Arc<AppState>, cx: &mut MutableAppContext) -> Self {
- Self {
- project: Project::local(
- app_state.client.clone(),
- app_state.user_store.clone(),
- app_state.languages.clone(),
- app_state.fs.clone(),
- cx,
- ),
- client: app_state.client.clone(),
- fs: app_state.fs.clone(),
- themes: app_state.themes.clone(),
- languages: app_state.languages.clone(),
- user_store: app_state.user_store.clone(),
- channel_list: app_state.channel_list.clone(),
- }
+ build_workspace: |project, _, cx| Workspace::new(project, cx),
+ build_window_options: || Default::default(),
+ })
}
}
@@ -708,7 +671,6 @@ pub struct Workspace {
user_store: ModelHandle<client::UserStore>,
remote_entity_subscription: Option<Subscription>,
fs: Arc<dyn Fs>,
- themes: Arc<ThemeRegistry>,
modal: Option<AnyViewHandle>,
center: PaneGroup,
left_sidebar: ViewHandle<Sidebar>,
@@ -744,8 +706,8 @@ enum FollowerItem {
}
impl Workspace {
- pub fn new(params: &WorkspaceParams, cx: &mut ViewContext<Self>) -> Self {
- cx.observe(¶ms.project, |_, project, cx| {
+ pub fn new(project: ModelHandle<Project>, cx: &mut ViewContext<Self>) -> Self {
+ cx.observe(&project, |_, project, cx| {
if project.read(cx).is_read_only() {
cx.blur();
}
@@ -753,7 +715,7 @@ impl Workspace {
})
.detach();
- cx.subscribe(¶ms.project, move |this, project, event, cx| {
+ cx.subscribe(&project, move |this, project, event, cx| {
match event {
project::Event::RemoteIdChanged(remote_id) => {
this.project_remote_id_changed(*remote_id, cx);
@@ -785,8 +747,11 @@ impl Workspace {
cx.focus(&pane);
cx.emit(Event::PaneAdded(pane.clone()));
- let mut current_user = params.user_store.read(cx).watch_current_user().clone();
- let mut connection_status = params.client.status().clone();
+ let fs = project.read(cx).fs().clone();
+ let user_store = project.read(cx).user_store();
+ let client = project.read(cx).client();
+ let mut current_user = user_store.read(cx).watch_current_user().clone();
+ let mut connection_status = client.status().clone();
let _observe_current_user = cx.spawn_weak(|this, mut cx| async move {
current_user.recv().await;
connection_status.recv().await;
@@ -826,14 +791,13 @@ impl Workspace {
active_pane: pane.clone(),
status_bar,
notifications: Default::default(),
- client: params.client.clone(),
+ client,
remote_entity_subscription: None,
- user_store: params.user_store.clone(),
- fs: params.fs.clone(),
- themes: params.themes.clone(),
+ user_store,
+ fs,
left_sidebar,
right_sidebar,
- project: params.project.clone(),
+ project,
leader_state: Default::default(),
follower_states_by_leader: Default::default(),
last_leaders_by_pane: Default::default(),
@@ -867,10 +831,6 @@ impl Workspace {
&self.project
}
- pub fn themes(&self) -> Arc<ThemeRegistry> {
- self.themes.clone()
- }
-
pub fn worktrees<'a>(
&self,
cx: &'a AppContext,
@@ -2203,8 +2163,7 @@ impl std::fmt::Debug for OpenPaths {
}
}
-fn open(action: &Open, cx: &mut MutableAppContext) {
- let app_state = action.0.clone();
+fn open(_: &Open, cx: &mut MutableAppContext) {
let mut paths = cx.prompt_for_paths(PathPromptOptions {
files: true,
directories: true,
@@ -2212,7 +2171,7 @@ fn open(action: &Open, cx: &mut MutableAppContext) {
});
cx.spawn(|mut cx| async move {
if let Some(paths) = paths.recv().await.flatten() {
- cx.update(|cx| cx.dispatch_global_action(OpenPaths { paths, app_state }));
+ cx.update(|cx| cx.dispatch_global_action(OpenPaths { paths }));
}
})
.detach();
@@ -2320,7 +2279,7 @@ fn open_new(app_state: &Arc<AppState>, cx: &mut MutableAppContext) {
app_state.fs.clone(),
cx,
);
- (app_state.build_workspace)(project, &app_state, cx)
+ (app_state.build_workspace)(project, app_state, cx)
});
- cx.dispatch_action(window_id, vec![workspace.id()], &OpenNew(app_state.clone()));
+ cx.dispatch_action(window_id, vec![workspace.id()], &OpenNew);
}
@@ -12,7 +12,7 @@ use cli::{
use client::{
self,
http::{self, HttpClient},
- ChannelList, UserStore, ZED_SECRET_CLIENT_TOKEN,
+ UserStore, ZED_SECRET_CLIENT_TOKEN,
};
use fs::OpenOptions;
use futures::{
@@ -133,15 +133,12 @@ fn main() {
let client = client::Client::new(http.clone());
let mut languages = languages::build_language_registry(login_shell_env_loaded);
let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http.clone(), cx));
- let channel_list =
- cx.add_model(|cx| ChannelList::new(user_store.clone(), client.clone(), cx));
auto_update::init(http, client::ZED_SERVER_URL.clone(), cx);
project::Project::init(&client);
client::Channel::init(&client);
client::init(client.clone(), cx);
command_palette::init(cx);
- workspace::init(&client, cx);
editor::init(cx);
go_to_line::init(cx);
file_finder::init(cx);
@@ -192,33 +189,33 @@ fn main() {
let app_state = Arc::new(AppState {
languages,
themes,
- channel_list,
client: client.clone(),
user_store,
fs,
build_window_options,
build_workspace,
});
+ workspace::init(app_state.clone(), cx);
journal::init(app_state.clone(), cx);
- theme_selector::init(cx);
+ theme_selector::init(app_state.clone(), cx);
zed::init(&app_state, cx);
- cx.set_menus(menus::menus(&app_state.clone()));
+ cx.set_menus(menus::menus());
if stdout_is_a_pty() {
cx.platform().activate(true);
let paths = collect_path_args();
if paths.is_empty() {
- cx.dispatch_global_action(OpenNew(app_state.clone()));
+ cx.dispatch_global_action(OpenNew);
} else {
- cx.dispatch_global_action(OpenPaths { paths, app_state });
+ cx.dispatch_global_action(OpenPaths { paths });
}
} else {
if let Ok(Some(connection)) = cli_connections_rx.try_next() {
cx.spawn(|cx| handle_cli_connection(connection, app_state.clone(), cx))
.detach();
} else {
- cx.dispatch_global_action(OpenNew(app_state.clone()));
+ cx.dispatch_global_action(OpenNew);
}
cx.spawn(|cx| async move {
while let Some(connection) = cli_connections_rx.next().await {
@@ -1,9 +1,7 @@
-use crate::AppState;
use gpui::{Menu, MenuItem};
-use std::sync::Arc;
#[cfg(target_os = "macos")]
-pub fn menus(state: &Arc<AppState>) -> Vec<Menu<'static>> {
+pub fn menus() -> Vec<Menu<'static>> {
vec![
Menu {
name: "Zed",
@@ -33,12 +31,12 @@ pub fn menus(state: &Arc<AppState>) -> Vec<Menu<'static>> {
items: vec![
MenuItem::Action {
name: "New",
- action: Box::new(workspace::OpenNew(state.clone())),
+ action: Box::new(workspace::OpenNew),
},
MenuItem::Separator,
MenuItem::Action {
name: "Openβ¦",
- action: Box::new(workspace::Open(state.clone())),
+ action: Box::new(workspace::Open),
},
],
},
@@ -1,13 +1,3 @@
-use crate::{build_window_options, build_workspace, AppState};
-use assets::Assets;
-use client::{test::FakeHttpClient, ChannelList, Client, UserStore};
-use gpui::MutableAppContext;
-use language::LanguageRegistry;
-use project::fs::FakeFs;
-use settings::Settings;
-use std::sync::Arc;
-use theme::ThemeRegistry;
-
#[cfg(test)]
#[ctor::ctor]
fn init_logger() {
@@ -15,32 +5,3 @@ fn init_logger() {
env_logger::init();
}
}
-
-pub fn test_app_state(cx: &mut MutableAppContext) -> Arc<AppState> {
- let settings = Settings::test(cx);
- editor::init(cx);
- cx.set_global(settings);
- let themes = ThemeRegistry::new(Assets, cx.font_cache().clone());
- let http = FakeHttpClient::with_404_response();
- let client = Client::new(http.clone());
- let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http, cx));
- let languages = LanguageRegistry::test();
- languages.add(Arc::new(language::Language::new(
- language::LanguageConfig {
- name: "Rust".into(),
- path_suffixes: vec!["rs".to_string()],
- ..Default::default()
- },
- Some(tree_sitter_rust::language()),
- )));
- Arc::new(AppState {
- themes,
- languages: Arc::new(languages),
- channel_list: cx.add_model(|cx| ChannelList::new(user_store.clone(), client.clone(), cx)),
- client,
- user_store,
- fs: FakeFs::new(cx.background().clone()),
- build_window_options,
- build_workspace,
- })
-}
@@ -31,7 +31,7 @@ use std::{
};
use util::ResultExt;
pub use workspace;
-use workspace::{AppState, Workspace, WorkspaceParams};
+use workspace::{AppState, Workspace};
actions!(
zed,
@@ -139,18 +139,7 @@ pub fn build_workspace(
})
.detach();
- let workspace_params = WorkspaceParams {
- project,
- client: app_state.client.clone(),
- fs: app_state.fs.clone(),
- languages: app_state.languages.clone(),
- themes: app_state.themes.clone(),
- user_store: app_state.user_store.clone(),
- channel_list: app_state.channel_list.clone(),
- };
- let workspace = Workspace::new(&workspace_params, cx);
- let project = workspace.project().clone();
-
+ let workspace = Workspace::new(project.clone(), cx);
let theme_names = app_state.themes.list().collect();
let language_names = app_state.languages.language_names();
@@ -313,43 +302,45 @@ mod tests {
use assets::Assets;
use editor::{Autoscroll, DisplayPoint, Editor};
use gpui::{AssetSource, MutableAppContext, TestAppContext, ViewHandle};
- use project::{Fs, ProjectPath};
+ use project::ProjectPath;
use serde_json::json;
use std::{
collections::HashSet,
path::{Path, PathBuf},
};
- use test::test_app_state;
use theme::{Theme, ThemeRegistry, DEFAULT_THEME_NAME};
- use util::test::temp_tree;
use workspace::{
open_paths, pane, Item, ItemHandle, OpenNew, Pane, SplitDirection, WorkspaceHandle,
};
#[gpui::test]
async fn test_open_paths_action(cx: &mut TestAppContext) {
- let app_state = cx.update(test_app_state);
- let dir = temp_tree(json!({
- "a": {
- "aa": null,
- "ab": null,
- },
- "b": {
- "ba": null,
- "bb": null,
- },
- "c": {
- "ca": null,
- "cb": null,
- },
- }));
+ let app_state = init(cx);
+ app_state
+ .fs
+ .as_fake()
+ .insert_tree(
+ "/root",
+ json!({
+ "a": {
+ "aa": null,
+ "ab": null,
+ },
+ "b": {
+ "ba": null,
+ "bb": null,
+ },
+ "c": {
+ "ca": null,
+ "cb": null,
+ },
+ }),
+ )
+ .await;
cx.update(|cx| {
open_paths(
- &[
- dir.path().join("a").to_path_buf(),
- dir.path().join("b").to_path_buf(),
- ],
+ &[PathBuf::from("/root/a"), PathBuf::from("/root/b")],
&app_state,
cx,
)
@@ -357,7 +348,7 @@ mod tests {
.await;
assert_eq!(cx.window_ids().len(), 1);
- cx.update(|cx| open_paths(&[dir.path().join("a").to_path_buf()], &app_state, cx))
+ cx.update(|cx| open_paths(&[PathBuf::from("/root/a")], &app_state, cx))
.await;
assert_eq!(cx.window_ids().len(), 1);
let workspace_1 = cx.root_view::<Workspace>(cx.window_ids()[0]).unwrap();
@@ -369,10 +360,7 @@ mod tests {
cx.update(|cx| {
open_paths(
- &[
- dir.path().join("b").to_path_buf(),
- dir.path().join("c").to_path_buf(),
- ],
+ &[PathBuf::from("/root/b"), PathBuf::from("/root/c")],
&app_state,
cx,
)
@@ -383,11 +371,8 @@ mod tests {
#[gpui::test]
async fn test_new_empty_workspace(cx: &mut TestAppContext) {
- let app_state = cx.update(test_app_state);
- cx.update(|cx| {
- workspace::init(&app_state.client, cx);
- });
- cx.dispatch_global_action(workspace::OpenNew(app_state.clone()));
+ let app_state = init(cx);
+ cx.dispatch_global_action(workspace::OpenNew);
let window_id = *cx.window_ids().first().unwrap();
let workspace = cx.root_view::<Workspace>(window_id).unwrap();
let editor = workspace.update(cx, |workspace, cx| {
@@ -414,7 +399,7 @@ mod tests {
#[gpui::test]
async fn test_open_entry(cx: &mut TestAppContext) {
- let app_state = cx.update(test_app_state);
+ let app_state = init(cx);
app_state
.fs
.as_fake()
@@ -429,18 +414,10 @@ mod tests {
}),
)
.await;
- let params = cx.update(|cx| WorkspaceParams::local(&app_state, cx));
- let (_, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
- params
- .project
- .update(cx, |project, cx| {
- project.find_or_create_local_worktree("/root", true, cx)
- })
- .await
- .unwrap();
- cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx))
- .await;
+ let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
+ let (_, workspace) = cx.add_window(|cx| Workspace::new(project, cx));
+
let entries = cx.read(|cx| workspace.file_project_paths(cx));
let file1 = entries[0].clone();
let file2 = entries[1].clone();
@@ -535,7 +512,8 @@ mod tests {
#[gpui::test]
async fn test_open_paths(cx: &mut TestAppContext) {
- let app_state = cx.update(test_app_state);
+ let app_state = init(cx);
+
let fs = app_state.fs.as_fake();
fs.insert_dir("/dir1").await;
fs.insert_dir("/dir2").await;
@@ -544,17 +522,8 @@ mod tests {
fs.insert_file("/dir2/b.txt", "".into()).await;
fs.insert_file("/dir3/c.txt", "".into()).await;
- let params = cx.update(|cx| WorkspaceParams::local(&app_state, cx));
- let (_, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
- params
- .project
- .update(cx, |project, cx| {
- project.find_or_create_local_worktree("/dir1", true, cx)
- })
- .await
- .unwrap();
- cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx))
- .await;
+ let project = Project::test(app_state.fs.clone(), ["/dir1".as_ref()], cx).await;
+ let (_, workspace) = cx.add_window(|cx| Workspace::new(project, cx));
// Open a file within an existing worktree.
cx.update(|cx| {
@@ -655,19 +624,15 @@ mod tests {
#[gpui::test]
async fn test_save_conflicting_item(cx: &mut TestAppContext) {
- let app_state = cx.update(test_app_state);
- let fs = app_state.fs.as_fake();
- fs.insert_tree("/root", json!({ "a.txt": "" })).await;
-
- let params = cx.update(|cx| WorkspaceParams::local(&app_state, cx));
- let (window_id, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
- params
- .project
- .update(cx, |project, cx| {
- project.find_or_create_local_worktree("/root", true, cx)
- })
- .await
- .unwrap();
+ let app_state = init(cx);
+ app_state
+ .fs
+ .as_fake()
+ .insert_tree("/root", json!({ "a.txt": "" }))
+ .await;
+
+ let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
+ let (window_id, workspace) = cx.add_window(|cx| Workspace::new(project, cx));
// Open a file within an existing worktree.
cx.update(|cx| {
@@ -687,7 +652,11 @@ mod tests {
editor.handle_input(&editor::Input("x".into()), cx)
})
});
- fs.insert_file("/root/a.txt", "changed".to_string()).await;
+ app_state
+ .fs
+ .as_fake()
+ .insert_file("/root/a.txt", "changed".to_string())
+ .await;
editor
.condition(&cx, |editor, cx| editor.has_conflict(cx))
.await;
@@ -704,21 +673,16 @@ mod tests {
#[gpui::test]
async fn test_open_and_save_new_file(cx: &mut TestAppContext) {
- let app_state = cx.update(test_app_state);
+ let app_state = init(cx);
app_state.fs.as_fake().insert_dir("/root").await;
- let params = cx.update(|cx| WorkspaceParams::local(&app_state, cx));
- let (window_id, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
- params
- .project
- .update(cx, |project, cx| {
- project.find_or_create_local_worktree("/root", true, cx)
- })
- .await
- .unwrap();
+
+ let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
+ project.update(cx, |project, _| project.languages().add(rust_lang()));
+ let (window_id, workspace) = cx.add_window(|cx| Workspace::new(project, cx));
let worktree = cx.read(|cx| workspace.read(cx).worktrees(cx).next().unwrap());
// Create a new untitled buffer
- cx.dispatch_action(window_id, OpenNew(app_state.clone()));
+ cx.dispatch_action(window_id, OpenNew);
let editor = workspace.read_with(cx, |workspace, cx| {
workspace
.active_item(cx)
@@ -773,18 +737,11 @@ mod tests {
// Open the same newly-created file in another pane item. The new editor should reuse
// the same buffer.
- cx.dispatch_action(window_id, OpenNew(app_state.clone()));
+ cx.dispatch_action(window_id, OpenNew);
workspace
.update(cx, |workspace, cx| {
workspace.split_pane(workspace.active_pane().clone(), SplitDirection::Right, cx);
- workspace.open_path(
- ProjectPath {
- worktree_id: worktree.read(cx).id(),
- path: Path::new("the-new-name.rs").into(),
- },
- true,
- cx,
- )
+ workspace.open_path((worktree.read(cx).id(), "the-new-name.rs"), true, cx)
})
.await
.unwrap();
@@ -805,13 +762,15 @@ mod tests {
#[gpui::test]
async fn test_setting_language_when_saving_as_single_file_worktree(cx: &mut TestAppContext) {
- let app_state = cx.update(test_app_state);
+ let app_state = init(cx);
app_state.fs.as_fake().insert_dir("/root").await;
- let params = cx.update(|cx| WorkspaceParams::local(&app_state, cx));
- let (window_id, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
+
+ let project = Project::test(app_state.fs.clone(), [], cx).await;
+ project.update(cx, |project, _| project.languages().add(rust_lang()));
+ let (window_id, workspace) = cx.add_window(|cx| Workspace::new(project, cx));
// Create a new untitled buffer
- cx.dispatch_action(window_id, OpenNew(app_state.clone()));
+ cx.dispatch_action(window_id, OpenNew);
let editor = workspace.read_with(cx, |workspace, cx| {
workspace
.active_item(cx)
@@ -842,10 +801,9 @@ mod tests {
#[gpui::test]
async fn test_pane_actions(cx: &mut TestAppContext) {
- cx.foreground().forbid_parking();
+ init(cx);
- cx.update(|cx| pane::init(cx));
- let app_state = cx.update(test_app_state);
+ let app_state = cx.update(AppState::test);
app_state
.fs
.as_fake()
@@ -861,17 +819,9 @@ mod tests {
)
.await;
- let params = cx.update(|cx| WorkspaceParams::local(&app_state, cx));
- let (window_id, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
- params
- .project
- .update(cx, |project, cx| {
- project.find_or_create_local_worktree("/root", true, cx)
- })
- .await
- .unwrap();
- cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx))
- .await;
+ let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
+ let (window_id, workspace) = cx.add_window(|cx| Workspace::new(project, cx));
+
let entries = cx.read(|cx| workspace.file_project_paths(cx));
let file1 = entries[0].clone();
@@ -926,7 +876,7 @@ mod tests {
#[gpui::test]
async fn test_navigation(cx: &mut TestAppContext) {
- let app_state = cx.update(test_app_state);
+ let app_state = init(cx);
app_state
.fs
.as_fake()
@@ -941,17 +891,10 @@ mod tests {
}),
)
.await;
- let params = cx.update(|cx| WorkspaceParams::local(&app_state, cx));
- let (_, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
- params
- .project
- .update(cx, |project, cx| {
- project.find_or_create_local_worktree("/root", true, cx)
- })
- .await
- .unwrap();
- cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx))
- .await;
+
+ let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
+ let (_, workspace) = cx.add_window(|cx| Workspace::new(project.clone(), cx));
+
let entries = cx.read(|cx| workspace.file_project_paths(cx));
let file1 = entries[0].clone();
let file2 = entries[1].clone();
@@ -990,7 +933,7 @@ mod tests {
editor.newline(&Default::default(), cx);
editor.move_down(&Default::default(), cx);
editor.move_down(&Default::default(), cx);
- editor.save(params.project.clone(), cx)
+ editor.save(project.clone(), cx)
})
.await
.unwrap();
@@ -1104,7 +1047,6 @@ mod tests {
.unwrap();
app_state
.fs
- .as_fake()
.remove_file(Path::new("/root/a/file2"), Default::default())
.await
.unwrap();
@@ -1219,4 +1161,29 @@ mod tests {
}
assert!(has_default_theme);
}
+
+ fn init(cx: &mut TestAppContext) -> Arc<AppState> {
+ cx.foreground().forbid_parking();
+ cx.update(|cx| {
+ let mut app_state = AppState::test(cx);
+ let state = Arc::get_mut(&mut app_state).unwrap();
+ state.build_workspace = build_workspace;
+ state.build_window_options = build_window_options;
+ workspace::init(app_state.clone(), cx);
+ editor::init(cx);
+ pane::init(cx);
+ app_state
+ })
+ }
+
+ fn rust_lang() -> Arc<language::Language> {
+ Arc::new(language::Language::new(
+ language::LanguageConfig {
+ name: "Rust".into(),
+ path_suffixes: vec!["rs".to_string()],
+ ..Default::default()
+ },
+ Some(tree_sitter_rust::language()),
+ ))
+ }
}