Cargo.lock 🔗
@@ -16,7 +16,6 @@ dependencies = [
"project",
"smallvec",
"ui",
- "util",
"workspace",
]
Conrad Irwin created
Release Notes:
- Allow creating new untitled buffers in remote projects
TODO:
- Add a Test
- Fix version number check
Cargo.lock | 1
crates/activity_indicator/Cargo.toml | 1
crates/activity_indicator/src/activity_indicator.rs | 43 +++++---
crates/auto_update/src/auto_update.rs | 6
crates/collab/src/rpc.rs | 47 +++++++++
crates/collab/src/rpc/connection_pool.rs | 32 ++++++
crates/collab/src/tests/dev_server_tests.rs | 30 ++++++
crates/collab/src/tests/integration_tests.rs | 3
crates/editor/src/editor.rs | 72 +++++++++-----
crates/editor/src/editor_tests.rs | 12 -
crates/editor/src/git.rs | 40 +++----
crates/editor/src/rust_analyzer_ext.rs | 14 +-
crates/feedback/src/feedback_modal.rs | 8 -
crates/project/src/project.rs | 43 +++++++-
crates/project/src/project_tests.rs | 4
crates/project_panel/src/project_panel.rs | 4
crates/rpc/proto/zed.proto | 8 +
crates/rpc/src/proto.rs | 5
crates/zed/src/zed.rs | 14 +-
19 files changed, 276 insertions(+), 111 deletions(-)
@@ -16,7 +16,6 @@ dependencies = [
"project",
"smallvec",
"ui",
- "util",
"workspace",
]
@@ -23,7 +23,6 @@ language.workspace = true
project.workspace = true
smallvec.workspace = true
ui.workspace = true
-util.workspace = true
workspace.workspace = true
[dev-dependencies]
@@ -12,7 +12,6 @@ use project::{LanguageServerProgress, Project};
use smallvec::SmallVec;
use std::{cmp::Reverse, fmt::Write, sync::Arc};
use ui::prelude::*;
-use util::ResultExt;
use workspace::{item::ItemHandle, StatusItemView, Workspace};
actions!(activity_indicator, [ShowErrorMessage]);
@@ -82,27 +81,37 @@ impl ActivityIndicator {
}
});
- cx.subscribe(&this, move |workspace, _, event, cx| match event {
+ cx.subscribe(&this, move |_, _, event, cx| match event {
Event::ShowError { lsp_name, error } => {
- if let Some(buffer) = project
- .update(cx, |project, cx| project.create_buffer(error, None, cx))
- .log_err()
- {
- buffer.update(cx, |buffer, cx| {
+ let create_buffer = project.update(cx, |project, cx| project.create_buffer(cx));
+ let project = project.clone();
+ let error = error.clone();
+ let lsp_name = lsp_name.clone();
+ cx.spawn(|workspace, mut cx| async move {
+ let buffer = create_buffer.await?;
+ buffer.update(&mut cx, |buffer, cx| {
buffer.edit(
- [(0..0, format!("Language server error: {}\n\n", lsp_name))],
+ [(
+ 0..0,
+ format!("Language server error: {}\n\n{}", lsp_name, error),
+ )],
None,
cx,
);
- });
- workspace.add_item_to_active_pane(
- Box::new(
- cx.new_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx)),
- ),
- None,
- cx,
- );
- }
+ })?;
+ workspace.update(&mut cx, |workspace, cx| {
+ workspace.add_item_to_active_pane(
+ Box::new(cx.new_view(|cx| {
+ Editor::for_buffer(buffer, Some(project.clone()), cx)
+ })),
+ None,
+ cx,
+ );
+ })?;
+
+ anyhow::Ok(())
+ })
+ .detach();
}
})
.detach();
@@ -221,9 +221,9 @@ fn view_release_notes_locally(workspace: &mut Workspace, cx: &mut ViewContext<Wo
workspace
.update(&mut cx, |workspace, cx| {
let project = workspace.project().clone();
- let buffer = project
- .update(cx, |project, cx| project.create_buffer("", markdown, cx))
- .expect("creating buffers on a local workspace always succeeds");
+ let buffer = project.update(cx, |project, cx| {
+ project.create_local_buffer("", markdown, cx)
+ });
buffer.update(cx, |buffer, cx| {
buffer.edit([(0..0, body.release_notes)], None, cx)
});
@@ -74,6 +74,8 @@ use tracing::{
};
use util::http::IsahcHttpClient;
+use self::connection_pool::VersionedMessage;
+
pub const RECONNECT_TIMEOUT: Duration = Duration::from_secs(30);
// kubernetes gives terminated pods 10s to shutdown gracefully. After they're gone, we can clean up old resources.
@@ -465,6 +467,9 @@ impl Server {
.add_request_handler(user_handler(
forward_mutating_project_request::<proto::ApplyCompletionAdditionalEdits>,
))
+ .add_request_handler(user_handler(
+ forward_versioned_mutating_project_request::<proto::OpenNewBuffer>,
+ ))
.add_request_handler(user_handler(
forward_mutating_project_request::<proto::ResolveCompletionDocumentation>,
))
@@ -505,7 +510,7 @@ impl Server {
forward_mutating_project_request::<proto::OnTypeFormatting>,
))
.add_request_handler(user_handler(
- forward_mutating_project_request::<proto::SaveBuffer>,
+ forward_versioned_mutating_project_request::<proto::SaveBuffer>,
))
.add_request_handler(user_handler(
forward_mutating_project_request::<proto::BlameBuffer>,
@@ -2677,11 +2682,51 @@ where
T: EntityMessage + RequestMessage,
{
let project_id = ProjectId::from_proto(request.remote_entity_id());
+
+ let host_connection_id = session
+ .db()
+ .await
+ .host_for_mutating_project_request(project_id, session.connection_id, session.user_id())
+ .await?;
+ let payload = session
+ .peer
+ .forward_request(session.connection_id, host_connection_id, request)
+ .await?;
+ response.send(payload)?;
+ Ok(())
+}
+
+/// forward a project request to the host. These requests are disallowed
+/// for guests.
+async fn forward_versioned_mutating_project_request<T>(
+ request: T,
+ response: Response<T>,
+ session: UserSession,
+) -> Result<()>
+where
+ T: EntityMessage + RequestMessage + VersionedMessage,
+{
+ let project_id = ProjectId::from_proto(request.remote_entity_id());
+
let host_connection_id = session
.db()
.await
.host_for_mutating_project_request(project_id, session.connection_id, session.user_id())
.await?;
+ if let Some(host_version) = session
+ .connection_pool()
+ .await
+ .connection(host_connection_id)
+ .map(|c| c.zed_version)
+ {
+ if let Some(min_required_version) = request.required_host_version() {
+ if min_required_version > host_version {
+ return Err(anyhow!(ErrorCode::RemoteUpgradeRequired
+ .with_tag("required", &min_required_version.to_string())))?;
+ }
+ }
+ }
+
let payload = session
.peer
.forward_request(session.connection_id, host_connection_id, request)
@@ -21,7 +21,7 @@ struct ConnectedPrincipal {
connection_ids: HashSet<ConnectionId>,
}
-#[derive(Debug, Serialize)]
+#[derive(Copy, Clone, Debug, Serialize, PartialOrd, PartialEq, Eq, Ord)]
pub struct ZedVersion(pub SemanticVersion);
impl fmt::Display for ZedVersion {
@@ -34,6 +34,32 @@ impl ZedVersion {
pub fn can_collaborate(&self) -> bool {
self.0 >= SemanticVersion::new(0, 129, 2)
}
+
+ pub fn with_save_as() -> ZedVersion {
+ ZedVersion(SemanticVersion::new(0, 134, 0))
+ }
+}
+
+pub trait VersionedMessage {
+ fn required_host_version(&self) -> Option<ZedVersion> {
+ None
+ }
+}
+
+impl VersionedMessage for proto::SaveBuffer {
+ fn required_host_version(&self) -> Option<ZedVersion> {
+ if self.new_path.is_some() {
+ Some(ZedVersion::with_save_as())
+ } else {
+ None
+ }
+ }
+}
+
+impl VersionedMessage for proto::OpenNewBuffer {
+ fn required_host_version(&self) -> Option<ZedVersion> {
+ Some(ZedVersion::with_save_as())
+ }
}
#[derive(Serialize)]
@@ -50,6 +76,10 @@ impl ConnectionPool {
self.channels.clear();
}
+ pub fn connection(&mut self, connection_id: ConnectionId) -> Option<&Connection> {
+ self.connections.get(&connection_id)
+ }
+
#[instrument(skip(self))]
pub fn add_connection(
&mut self,
@@ -398,3 +398,33 @@ async fn test_save_as_remote(cx1: &mut gpui::TestAppContext, cx2: &mut gpui::Tes
"remote\nremote\nremote"
);
}
+
+#[gpui::test]
+async fn test_new_file_remote(cx1: &mut gpui::TestAppContext, cx2: &mut gpui::TestAppContext) {
+ let (server, client1) = TestServer::start1(cx1).await;
+
+ // Creating a project with a path that does exist should not fail
+ let (dev_server, remote_workspace) =
+ create_remote_project(&server, client1.app_state.clone(), cx1, cx2).await;
+
+ let mut cx = VisualTestContext::from_window(remote_workspace.into(), cx1);
+
+ cx.simulate_keystrokes("cmd-n");
+ cx.simulate_input("new!");
+ cx.simulate_keystrokes("cmd-shift-s");
+ cx.simulate_input("2.txt");
+ cx.simulate_keystrokes("enter");
+
+ cx.executor().run_until_parked();
+
+ let title = remote_workspace
+ .update(&mut cx, |ws, cx| {
+ ws.active_item(cx).unwrap().tab_description(0, &cx).unwrap()
+ })
+ .unwrap();
+
+ assert_eq!(title, "2.txt");
+
+ let path = Path::new("/remote/2.txt");
+ assert_eq!(dev_server.fs().load(&path).await.unwrap(), "new!");
+}
@@ -2450,7 +2450,8 @@ async fn test_propagate_saves_and_fs_changes(
});
let new_buffer_a = project_a
- .update(cx_a, |p, cx| p.create_buffer("", None, cx))
+ .update(cx_a, |p, cx| p.create_buffer(cx))
+ .await
.unwrap();
let new_buffer_id = new_buffer_a.read_with(cx_a, |buffer, _| buffer.remote_id());
@@ -99,7 +99,7 @@ use project::{
CodeAction, Completion, FormatTrigger, Item, Location, Project, ProjectPath, ProjectTransaction,
};
use rand::prelude::*;
-use rpc::proto::*;
+use rpc::{proto::*, ErrorExt};
use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
use selections_collection::{resolve_multiple, MutableSelectionsCollection, SelectionsCollection};
use serde::{Deserialize, Serialize};
@@ -131,7 +131,7 @@ use ui::{
};
use util::{defer, maybe, post_inc, RangeExt, ResultExt, TryFutureExt};
use workspace::item::{ItemHandle, PreviewTabsSettings};
-use workspace::notifications::NotificationId;
+use workspace::notifications::{DetachAndPromptErr, NotificationId};
use workspace::{
searchable::SearchEvent, ItemNavHistory, SplitDirection, ViewId, Workspace, WorkspaceId,
};
@@ -1610,18 +1610,27 @@ impl Editor {
cx: &mut ViewContext<Workspace>,
) {
let project = workspace.project().clone();
- if project.read(cx).is_remote() {
- cx.propagate();
- } else if let Some(buffer) = project
- .update(cx, |project, cx| project.create_buffer("", None, cx))
- .log_err()
- {
- workspace.add_item_to_active_pane(
- Box::new(cx.new_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx))),
- None,
- cx,
- );
- }
+ let create = project.update(cx, |project, cx| project.create_buffer(cx));
+
+ cx.spawn(|workspace, mut cx| async move {
+ let buffer = create.await?;
+ workspace.update(&mut cx, |workspace, cx| {
+ workspace.add_item_to_active_pane(
+ Box::new(
+ cx.new_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx)),
+ ),
+ None,
+ cx,
+ )
+ })
+ })
+ .detach_and_prompt_err("Failed to create buffer", cx, |e, _| match e.error_code() {
+ ErrorCode::RemoteUpgradeRequired => Some(format!(
+ "The remote instance of Zed does not support this yet. It must be upgraded to {}",
+ e.error_tag("required").unwrap_or("the latest version")
+ )),
+ _ => None,
+ });
}
pub fn new_file_in_direction(
@@ -1630,18 +1639,29 @@ impl Editor {
cx: &mut ViewContext<Workspace>,
) {
let project = workspace.project().clone();
- if project.read(cx).is_remote() {
- cx.propagate();
- } else if let Some(buffer) = project
- .update(cx, |project, cx| project.create_buffer("", None, cx))
- .log_err()
- {
- workspace.split_item(
- action.0,
- Box::new(cx.new_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx))),
- cx,
- );
- }
+ let create = project.update(cx, |project, cx| project.create_buffer(cx));
+ let direction = action.0;
+
+ cx.spawn(|workspace, mut cx| async move {
+ let buffer = create.await?;
+ workspace.update(&mut cx, move |workspace, cx| {
+ workspace.split_item(
+ direction,
+ Box::new(
+ cx.new_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx)),
+ ),
+ cx,
+ )
+ })?;
+ anyhow::Ok(())
+ })
+ .detach_and_prompt_err("Failed to create buffer", cx, |e, _| match e.error_code() {
+ ErrorCode::RemoteUpgradeRequired => Some(format!(
+ "The remote instance of Zed does not support this yet. It must be upgraded to {}",
+ e.error_tag("required").unwrap_or("the latest version")
+ )),
+ _ => None,
+ });
}
pub fn replica_id(&self, cx: &AppContext) -> ReplicaId {
@@ -7356,9 +7356,7 @@ async fn test_following(cx: &mut gpui::TestAppContext) {
let project = Project::test(fs, ["/file.rs".as_ref()], cx).await;
let buffer = project.update(cx, |project, cx| {
- let buffer = project
- .create_buffer(&sample_text(16, 8, 'a'), None, cx)
- .unwrap();
+ let buffer = project.create_local_buffer(&sample_text(16, 8, 'a'), None, cx);
cx.new_model(|cx| MultiBuffer::singleton(buffer, cx))
});
let leader = cx.add_window(|cx| build_editor(buffer.clone(), cx));
@@ -7565,12 +7563,8 @@ async fn test_following_with_multiple_excerpts(cx: &mut gpui::TestAppContext) {
let (buffer_1, buffer_2) = project.update(cx, |project, cx| {
(
- project
- .create_buffer("abc\ndef\nghi\njkl\n", None, cx)
- .unwrap(),
- project
- .create_buffer("mno\npqr\nstu\nvwx\n", None, cx)
- .unwrap(),
+ project.create_local_buffer("abc\ndef\nghi\njkl\n", None, cx),
+ project.create_local_buffer("mno\npqr\nstu\nvwx\n", None, cx),
)
});
@@ -108,10 +108,9 @@ mod tests {
let project = Project::test(fs, [], cx).await;
// buffer has two modified hunks with two rows each
- let buffer_1 = project
- .update(cx, |project, cx| {
- project.create_buffer(
- "
+ let buffer_1 = project.update(cx, |project, cx| {
+ project.create_local_buffer(
+ "
1.zero
1.ONE
1.TWO
@@ -120,13 +119,12 @@ mod tests {
1.FIVE
1.six
"
- .unindent()
- .as_str(),
- None,
- cx,
- )
- })
- .unwrap();
+ .unindent()
+ .as_str(),
+ None,
+ cx,
+ )
+ });
buffer_1.update(cx, |buffer, cx| {
buffer.set_diff_base(
Some(
@@ -146,10 +144,9 @@ mod tests {
});
// buffer has a deletion hunk and an insertion hunk
- let buffer_2 = project
- .update(cx, |project, cx| {
- project.create_buffer(
- "
+ let buffer_2 = project.update(cx, |project, cx| {
+ project.create_local_buffer(
+ "
2.zero
2.one
2.two
@@ -158,13 +155,12 @@ mod tests {
2.five
2.six
"
- .unindent()
- .as_str(),
- None,
- cx,
- )
- })
- .unwrap();
+ .unindent()
+ .as_str(),
+ None,
+ cx,
+ )
+ });
buffer_2.update(cx, |buffer, cx| {
buffer.set_diff_base(
Some(
@@ -97,15 +97,19 @@ pub fn expand_macro_recursively(
return Ok(());
}
- let buffer = project.update(&mut cx, |project, cx| {
- project.create_buffer(¯o_expansion.expansion, Some(rust_language), cx)
- })??;
+ let buffer = project
+ .update(&mut cx, |project, cx| project.create_buffer(cx))?
+ .await?;
workspace.update(&mut cx, |workspace, cx| {
- let buffer = cx.new_model(|cx| {
+ buffer.update(cx, |buffer, cx| {
+ buffer.edit([(0..0, macro_expansion.expansion)], None, cx);
+ buffer.set_language(Some(rust_language), cx)
+ });
+ let multibuffer = cx.new_model(|cx| {
MultiBuffer::singleton(buffer, cx).with_title(macro_expansion.name)
});
workspace.add_item_to_active_pane(
- Box::new(cx.new_view(|cx| Editor::for_multibuffer(buffer, Some(project), cx))),
+ Box::new(cx.new_view(|cx| Editor::for_multibuffer(multibuffer, Some(project), cx))),
None,
cx,
);
@@ -142,11 +142,9 @@ impl FeedbackModal {
cx.spawn(|workspace, mut cx| async move {
let markdown = markdown.await.log_err();
- let buffer = project
- .update(&mut cx, |project, cx| {
- project.create_buffer("", markdown, cx)
- })?
- .expect("creating buffers on a local workspace always succeeds");
+ let buffer = project.update(&mut cx, |project, cx| {
+ project.create_local_buffer("", markdown, cx)
+ })?;
workspace.update(&mut cx, |workspace, cx| {
let system_specs = SystemSpecs::new(cx);
@@ -665,6 +665,7 @@ impl Project {
client.add_model_request_handler(Self::handle_open_buffer_for_symbol);
client.add_model_request_handler(Self::handle_open_buffer_by_id);
client.add_model_request_handler(Self::handle_open_buffer_by_path);
+ client.add_model_request_handler(Self::handle_open_new_buffer);
client.add_model_request_handler(Self::handle_save_buffer);
client.add_model_message_handler(Self::handle_update_diff_base);
client.add_model_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
@@ -1955,21 +1956,41 @@ impl Project {
!self.is_local()
}
- pub fn create_buffer(
+ pub fn create_buffer(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<Model<Buffer>>> {
+ if self.is_remote() {
+ let create = self.client.request(proto::OpenNewBuffer {
+ project_id: self.remote_id().unwrap(),
+ });
+ cx.spawn(|this, mut cx| async move {
+ let response = create.await?;
+ let buffer_id = BufferId::new(response.buffer_id)?;
+
+ this.update(&mut cx, |this, cx| {
+ this.wait_for_remote_buffer(buffer_id, cx)
+ })?
+ .await
+ })
+ } else {
+ Task::ready(Ok(self.create_local_buffer("", None, cx)))
+ }
+ }
+
+ pub fn create_local_buffer(
&mut self,
text: &str,
language: Option<Arc<Language>>,
cx: &mut ModelContext<Self>,
- ) -> Result<Model<Buffer>> {
+ ) -> Model<Buffer> {
if self.is_remote() {
- return Err(anyhow!("creating buffers as a guest is not supported yet"));
+ panic!("called create_local_buffer on a remote project")
}
let buffer = cx.new_model(|cx| {
Buffer::local(text, cx)
.with_language(language.unwrap_or_else(|| language::PLAIN_TEXT.clone()), cx)
});
- self.register_buffer(&buffer, cx)?;
- Ok(buffer)
+ self.register_buffer(&buffer, cx)
+ .expect("creating local buffers always succeeds");
+ buffer
}
pub fn open_path(
@@ -9415,6 +9436,18 @@ impl Project {
Project::respond_to_open_buffer_request(this, buffer, peer_id, &mut cx)
}
+ async fn handle_open_new_buffer(
+ this: Model<Self>,
+ envelope: TypedEnvelope<proto::OpenNewBuffer>,
+ _: Arc<Client>,
+ mut cx: AsyncAppContext,
+ ) -> Result<proto::OpenBufferResponse> {
+ let buffer = this.update(&mut cx, |this, cx| this.create_local_buffer("", None, cx))?;
+ let peer_id = envelope.original_sender_id()?;
+
+ Project::respond_to_open_buffer_request(this, buffer, peer_id, &mut cx)
+ }
+
fn respond_to_open_buffer_request(
this: Model<Self>,
buffer: Model<Buffer>,
@@ -2931,9 +2931,7 @@ async fn test_save_as(cx: &mut gpui::TestAppContext) {
let languages = project.update(cx, |project, _| project.languages().clone());
languages.add(rust_lang());
- let buffer = project.update(cx, |project, cx| {
- project.create_buffer("", None, cx).unwrap()
- });
+ let buffer = project.update(cx, |project, cx| project.create_local_buffer("", None, cx));
buffer.update(cx, |buffer, cx| {
buffer.edit([(0..0, "abc")], None, cx);
assert!(buffer.is_dirty());
@@ -3394,7 +3394,9 @@ mod tests {
})
.unwrap();
- // "Save as"" the buffer, creating a new backing file for it
+ cx.executor().run_until_parked();
+
+ // "Save as" the buffer, creating a new backing file for it
let save_task = workspace
.update(cx, |workspace, cx| {
workspace.save_active_item(workspace::SaveIntent::Save, cx)
@@ -235,8 +235,9 @@ message Envelope {
RejoinRemoteProjectsResponse rejoin_remote_projects_response = 187;
RemoteProjectsUpdate remote_projects_update = 193;
- ValidateRemoteProjectRequest validate_remote_project_request = 194; // Current max
+ ValidateRemoteProjectRequest validate_remote_project_request = 194;
DeleteDevServer delete_dev_server = 195;
+ OpenNewBuffer open_new_buffer = 196; // Current max
}
reserved 158 to 161;
@@ -275,6 +276,7 @@ enum ErrorCode {
DevServerAlreadyOnline = 14;
DevServerOffline = 15;
RemoteProjectPathDoesNotExist = 16;
+ RemoteUpgradeRequired = 17;
reserved 6;
}
@@ -736,6 +738,10 @@ message OpenBufferById {
uint64 id = 2;
}
+message OpenNewBuffer {
+ uint64 project_id = 1;
+}
+
message OpenBufferResponse {
uint64 buffer_id = 1;
}
@@ -319,7 +319,8 @@ messages!(
(MultiLspQueryResponse, Background),
(RemoteProjectsUpdate, Foreground),
(ValidateRemoteProjectRequest, Background),
- (DeleteDevServer, Foreground)
+ (DeleteDevServer, Foreground),
+ (OpenNewBuffer, Foreground)
);
request_messages!(
@@ -377,6 +378,7 @@ request_messages!(
(OpenBufferById, OpenBufferResponse),
(OpenBufferByPath, OpenBufferResponse),
(OpenBufferForSymbol, OpenBufferForSymbolResponse),
+ (OpenNewBuffer, OpenBufferResponse),
(PerformRename, PerformRenameResponse),
(Ping, Ack),
(PrepareRename, PrepareRenameResponse),
@@ -453,6 +455,7 @@ entity_messages!(
LeaveProject,
MultiLspQuery,
OnTypeFormatting,
+ OpenNewBuffer,
OpenBufferById,
OpenBufferByPath,
OpenBufferForSymbol,
@@ -599,9 +599,9 @@ fn open_log_file(workspace: &mut Workspace, cx: &mut ViewContext<Workspace>) {
return;
};
let project = workspace.project().clone();
- let buffer = project
- .update(cx, |project, cx| project.create_buffer(&log, None, cx))
- .expect("creating buffers on a local workspace always succeeds");
+ let buffer = project.update(cx, |project, cx| {
+ project.create_local_buffer(&log, None, cx)
+ });
let buffer = cx.new_model(|cx| {
MultiBuffer::singleton(buffer, cx).with_title("Log".into())
@@ -812,8 +812,7 @@ fn open_telemetry_log_file(workspace: &mut Workspace, cx: &mut ViewContext<Works
workspace.update(&mut cx, |workspace, cx| {
let project = workspace.project().clone();
let buffer = project
- .update(cx, |project, cx| project.create_buffer("", None, cx))
- .expect("creating buffers on a local workspace always succeeds");
+ .update(cx, |project, cx| project.create_local_buffer("", None, cx));
buffer.update(cx, |buffer, cx| {
buffer.set_language(json, cx);
buffer.edit(
@@ -862,9 +861,7 @@ fn open_bundled_file(
workspace.with_local_workspace(cx, |workspace, cx| {
let project = workspace.project();
let buffer = project.update(cx, move |project, cx| {
- project
- .create_buffer(text.as_ref(), language, cx)
- .expect("creating buffers on a local workspace always succeeds")
+ project.create_local_buffer(text.as_ref(), language, cx)
});
let buffer = cx.new_model(|cx| {
MultiBuffer::singleton(buffer, cx).with_title(title.into())
@@ -1335,6 +1332,7 @@ mod tests {
})
})
.await;
+ cx.run_until_parked();
let workspace = cx
.update(|cx| cx.windows().first().unwrap().downcast::<Workspace>())