From 29cad65ce00bfff660e848cfb54b7097b4730403 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 4 Mar 2022 14:47:52 +0100 Subject: [PATCH] Open untitled buffers via the `Project` This allows the registration of such buffers in the project, which is necessary to correctly support `::save_buffer_as` and opens the door to sharing untitled buffers with guests in the future. Note that, for now, this disallows guests to create untitled buffers in the current window and will create a new window instead. This is because we don't yet have a global way of allocating a buffer's remote id (nor a way of saving such buffers in the host's worktree) and we instead rely on the local model ID, which could clash with the host's buffer IDs. I think we should revisit this once guests can share their untitled buffers with the host and other remote peers, as well as once we start keying operations by entry id. --- crates/editor/src/editor.rs | 12 ++++++-- crates/project/src/project.rs | 54 +++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 4b75627ef35f0f98287706224ce4b0d07fd2c994..857b33f625f88214e06436d37003f293c45e7a57 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -940,9 +940,15 @@ impl Editor { _: &workspace::OpenNew, cx: &mut ViewContext, ) { - let buffer = cx - .add_model(|cx| Buffer::new(0, "", cx).with_language(language::PLAIN_TEXT.clone(), cx)); - workspace.open_item(BufferItemHandle(buffer), cx); + let project = workspace.project(); + if project.read(cx).is_remote() { + cx.propagate_action(); + } else if let Some(buffer) = project + .update(cx, |project, cx| project.create_buffer(cx)) + .log_err() + { + workspace.open_item(BufferItemHandle(buffer), cx); + } } pub fn replica_id(&self, cx: &AppContext) -> ReplicaId { diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index a89317db90410d99c9d876b9206adace06ec8682..501cca28226847699d274aa5b364ff24fe630a67 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -687,6 +687,18 @@ impl Project { !self.is_local() } + pub fn create_buffer(&mut self, cx: &mut ModelContext) -> Result> { + if self.is_remote() { + return Err(anyhow!("creating buffers as a guest is not supported yet")); + } + + let buffer = cx.add_model(|cx| { + Buffer::new(self.replica_id(), "", cx).with_language(language::PLAIN_TEXT.clone(), cx) + }); + self.register_buffer(&buffer, None, cx)?; + Ok(buffer) + } + pub fn open_buffer( &mut self, path: impl Into, @@ -4113,6 +4125,48 @@ mod tests { assert_eq!(new_text, buffer.read_with(cx, |buffer, _| buffer.text())); } + #[gpui::test] + async fn test_save_as(cx: &mut gpui::TestAppContext) { + let fs = FakeFs::new(cx.background()); + fs.insert_tree("/dir", json!({})).await; + + let project = Project::test(fs.clone(), cx); + let (worktree, _) = project + .update(cx, |project, cx| { + project.find_or_create_local_worktree("/dir", true, cx) + }) + .await + .unwrap(); + let worktree_id = worktree.read_with(cx, |worktree, _| worktree.id()); + + let buffer = project.update(cx, |project, cx| project.create_buffer(cx).unwrap()); + buffer.update(cx, |buffer, cx| { + buffer.edit([0..0], "abc", cx); + assert!(buffer.is_dirty()); + assert!(!buffer.has_conflict()); + }); + project + .update(cx, |project, cx| { + project.save_buffer_as(buffer.clone(), "/dir/file1".into(), cx) + }) + .await + .unwrap(); + assert_eq!(fs.load(Path::new("/dir/file1")).await.unwrap(), "abc"); + buffer.read_with(cx, |buffer, cx| { + assert_eq!(buffer.file().unwrap().full_path(cx), Path::new("dir/file1")); + assert!(!buffer.is_dirty()); + assert!(!buffer.has_conflict()); + }); + + let opened_buffer = project + .update(cx, |project, cx| { + project.open_buffer((worktree_id, "file1"), cx) + }) + .await + .unwrap(); + assert_eq!(opened_buffer, buffer); + } + #[gpui::test(retries = 5)] async fn test_rescan_and_remote_updates(cx: &mut gpui::TestAppContext) { let dir = temp_tree(json!({