Skip COMMIT_EDITMSG contents when opening the file (#24146)

Kirill Bulatov created

Change summary

crates/git_ui/src/git_panel.rs               | 34 +++++++--
crates/project/src/buffer_store.rs           | 16 +++-
crates/project/src/lsp_store.rs              |  2 
crates/project/src/project.rs                | 74 ++++++++++++++-------
crates/proto/proto/zed.proto                 |  1 
crates/remote_server/src/headless_project.rs |  3 
crates/worktree/src/worktree.rs              | 22 +++++-
crates/worktree/src/worktree_tests.rs        |  4 
crates/zed/src/zed.rs                        |  2 
9 files changed, 110 insertions(+), 48 deletions(-)

Detailed changes

crates/git_ui/src/git_panel.rs 🔗

@@ -130,14 +130,34 @@ fn commit_message_buffer(
                 )
                 .await
                 .with_context(|| format!("creating commit message file {commit_message_file:?}"))?;
-                let buffer = project
+                let (worktree, relative_path) = project
                     .update(&mut cx, |project, cx| {
-                        project.open_local_buffer(&commit_message_file, cx)
+                        project.worktree_store().update(cx, |worktree_store, cx| {
+                            worktree_store.find_or_create_worktree(&commit_message_file, false, cx)
+                        })
                     })?
                     .await
                     .with_context(|| {
-                        format!("opening commit message buffer at {commit_message_file:?}",)
+                        format!("deriving worktree for commit message file {commit_message_file:?}")
                     })?;
+
+                let buffer = project
+                    .update(&mut cx, |project, cx| {
+                        project.buffer_store().update(cx, |buffer_store, cx| {
+                            buffer_store.open_buffer(
+                                ProjectPath {
+                                    worktree_id: worktree.read(cx).id(),
+                                    path: Arc::from(relative_path),
+                                },
+                                true,
+                                cx,
+                            )
+                        })
+                    })
+                    .with_context(|| {
+                        format!("opening buffer for commit message file {commit_message_file:?}")
+                    })?
+                    .await?;
                 Ok(buffer)
             })
         }
@@ -211,7 +231,6 @@ impl GitPanel {
     pub fn new(
         workspace: &mut Workspace,
         window: &mut Window,
-        commit_message_buffer: Option<Entity<Buffer>>,
         cx: &mut Context<Workspace>,
     ) -> Entity<Self> {
         let fs = workspace.app_state().fs.clone();
@@ -229,12 +248,7 @@ impl GitPanel {
             })
             .detach();
 
-            let commit_editor =
-                cx.new(|cx| commit_message_editor(commit_message_buffer, window, cx));
-            commit_editor.update(cx, |editor, cx| {
-                editor.clear(window, cx);
-            });
-
+            let commit_editor = cx.new(|cx| commit_message_editor(None, window, cx));
             let scroll_handle = UniformListScrollHandle::new();
 
             cx.subscribe_in(

crates/project/src/buffer_store.rs 🔗

@@ -329,6 +329,7 @@ impl RemoteBufferStore {
         &self,
         path: Arc<Path>,
         worktree: Entity<Worktree>,
+        skip_file_contents: bool,
         cx: &mut Context<BufferStore>,
     ) -> Task<Result<Entity<Buffer>>> {
         let worktree_id = worktree.read(cx).id().to_proto();
@@ -341,6 +342,7 @@ impl RemoteBufferStore {
                     project_id,
                     worktree_id,
                     path: path_string,
+                    skip_file_contents,
                 })
                 .await?;
             let buffer_id = BufferId::new(response.buffer_id)?;
@@ -786,10 +788,11 @@ impl LocalBufferStore {
         &self,
         path: Arc<Path>,
         worktree: Entity<Worktree>,
+        skip_file_contents: bool,
         cx: &mut Context<BufferStore>,
     ) -> Task<Result<Entity<Buffer>>> {
         let load_buffer = worktree.update(cx, |worktree, cx| {
-            let load_file = worktree.load_file(path.as_ref(), cx);
+            let load_file = worktree.load_file(path.as_ref(), skip_file_contents, cx);
             let reservation = cx.reserve_entity();
             let buffer_id = BufferId::from(reservation.entity_id().as_non_zero_u64());
             cx.spawn(move |_, mut cx| async move {
@@ -973,6 +976,7 @@ impl BufferStore {
     pub fn open_buffer(
         &mut self,
         project_path: ProjectPath,
+        skip_file_contents: bool,
         cx: &mut Context<Self>,
     ) -> Task<Result<Entity<Buffer>>> {
         if let Some(buffer) = self.get_by_path(&project_path, cx) {
@@ -991,8 +995,12 @@ impl BufferStore {
                     return Task::ready(Err(anyhow!("no such worktree")));
                 };
                 let load_buffer = match &self.state {
-                    BufferStoreState::Local(this) => this.open_buffer(path, worktree, cx),
-                    BufferStoreState::Remote(this) => this.open_buffer(path, worktree, cx),
+                    BufferStoreState::Local(this) => {
+                        this.open_buffer(path, worktree, skip_file_contents, cx)
+                    }
+                    BufferStoreState::Remote(this) => {
+                        this.open_buffer(path, worktree, skip_file_contents, cx)
+                    }
                 };
 
                 entry
@@ -1485,7 +1493,7 @@ impl BufferStore {
                 let buffers = this.update(&mut cx, |this, cx| {
                     project_paths
                         .into_iter()
-                        .map(|project_path| this.open_buffer(project_path, cx))
+                        .map(|project_path| this.open_buffer(project_path, false, cx))
                         .collect::<Vec<_>>()
                 })?;
                 for buffer_task in buffers {

crates/project/src/lsp_store.rs 🔗

@@ -5616,7 +5616,7 @@ impl LspStore {
             lsp_store
                 .update(&mut cx, |lsp_store, cx| {
                     lsp_store.buffer_store().update(cx, |buffer_store, cx| {
-                        buffer_store.open_buffer(project_path, cx)
+                        buffer_store.open_buffer(project_path, false, cx)
                     })
                 })?
                 .await

crates/project/src/project.rs 🔗

@@ -1933,7 +1933,21 @@ impl Project {
         }
 
         self.buffer_store.update(cx, |buffer_store, cx| {
-            buffer_store.open_buffer(path.into(), cx)
+            buffer_store.open_buffer(path.into(), false, cx)
+        })
+    }
+
+    pub fn open_buffer_without_contents(
+        &mut self,
+        path: impl Into<ProjectPath>,
+        cx: &mut Context<Self>,
+    ) -> Task<Result<Entity<Buffer>>> {
+        if self.is_disconnected(cx) {
+            return Task::ready(Err(anyhow!(ErrorCode::Disconnected)));
+        }
+
+        self.buffer_store.update(cx, |buffer_store, cx| {
+            buffer_store.open_buffer(path.into(), true, cx)
         })
     }
 
@@ -3937,14 +3951,25 @@ impl Project {
     ) -> Result<proto::OpenBufferResponse> {
         let peer_id = envelope.original_sender_id()?;
         let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
+        let skip_file_contents = envelope.payload.skip_file_contents;
         let open_buffer = this.update(&mut cx, |this, cx| {
-            this.open_buffer(
-                ProjectPath {
-                    worktree_id,
-                    path: PathBuf::from(envelope.payload.path).into(),
-                },
-                cx,
-            )
+            if skip_file_contents {
+                this.open_buffer_without_contents(
+                    ProjectPath {
+                        worktree_id,
+                        path: PathBuf::from(envelope.payload.path).into(),
+                    },
+                    cx,
+                )
+            } else {
+                this.open_buffer(
+                    ProjectPath {
+                        worktree_id,
+                        path: PathBuf::from(envelope.payload.path).into(),
+                    },
+                    cx,
+                )
+            }
         })?;
 
         let buffer = open_buffer.await?;
@@ -4073,12 +4098,10 @@ impl Project {
         .with_context(|| format!("creating commit message file {commit_message_file:?}"))?;
 
         let (worktree, relative_path) = this
-            .update(&mut cx, |headless_project, cx| {
-                headless_project
-                    .worktree_store
-                    .update(cx, |worktree_store, cx| {
-                        worktree_store.find_or_create_worktree(&commit_message_file, false, cx)
-                    })
+            .update(&mut cx, |project, cx| {
+                project.worktree_store.update(cx, |worktree_store, cx| {
+                    worktree_store.find_or_create_worktree(&commit_message_file, false, cx)
+                })
             })?
             .await
             .with_context(|| {
@@ -4086,18 +4109,17 @@ impl Project {
             })?;
 
         let buffer = this
-            .update(&mut cx, |headless_project, cx| {
-                headless_project
-                    .buffer_store
-                    .update(cx, |buffer_store, cx| {
-                        buffer_store.open_buffer(
-                            ProjectPath {
-                                worktree_id: worktree.read(cx).id(),
-                                path: Arc::from(relative_path),
-                            },
-                            cx,
-                        )
-                    })
+            .update(&mut cx, |project, cx| {
+                project.buffer_store.update(cx, |buffer_store, cx| {
+                    buffer_store.open_buffer(
+                        ProjectPath {
+                            worktree_id: worktree.read(cx).id(),
+                            path: Arc::from(relative_path),
+                        },
+                        true,
+                        cx,
+                    )
+                })
             })
             .with_context(|| {
                 format!("opening buffer for commit message file {commit_message_file:?}")

crates/proto/proto/zed.proto 🔗

@@ -795,6 +795,7 @@ message OpenBufferByPath {
     uint64 project_id = 1;
     uint64 worktree_id = 2;
     string path = 3;
+    bool skip_file_contents = 4;
 }
 
 message OpenBufferById {

crates/remote_server/src/headless_project.rs 🔗

@@ -421,6 +421,7 @@ impl HeadlessProject {
                         worktree_id,
                         path: PathBuf::from(message.payload.path).into(),
                     },
+                    message.payload.skip_file_contents,
                     cx,
                 )
             });
@@ -487,6 +488,7 @@ impl HeadlessProject {
                         worktree_id: worktree.read(cx).id(),
                         path: path.into(),
                     },
+                    false,
                     cx,
                 )
             });
@@ -749,6 +751,7 @@ impl HeadlessProject {
                                 worktree_id: worktree.read(cx).id(),
                                 path: Arc::from(relative_path),
                             },
+                            true,
                             cx,
                         )
                     })

crates/worktree/src/worktree.rs 🔗

@@ -862,9 +862,14 @@ impl Worktree {
         }
     }
 
-    pub fn load_file(&self, path: &Path, cx: &Context<Worktree>) -> Task<Result<LoadedFile>> {
+    pub fn load_file(
+        &self,
+        path: &Path,
+        skip_file_contents: bool,
+        cx: &Context<Worktree>,
+    ) -> Task<Result<LoadedFile>> {
         match self {
-            Worktree::Local(this) => this.load_file(path, cx),
+            Worktree::Local(this) => this.load_file(path, skip_file_contents, cx),
             Worktree::Remote(_) => {
                 Task::ready(Err(anyhow!("remote worktrees can't yet load files")))
             }
@@ -1582,7 +1587,12 @@ impl LocalWorktree {
         })
     }
 
-    fn load_file(&self, path: &Path, cx: &Context<Worktree>) -> Task<Result<LoadedFile>> {
+    fn load_file(
+        &self,
+        path: &Path,
+        skip_file_contents: bool,
+        cx: &Context<Worktree>,
+    ) -> Task<Result<LoadedFile>> {
         let path = Arc::from(path);
         let abs_path = self.absolutize(&path);
         let fs = self.fs.clone();
@@ -1591,7 +1601,11 @@ impl LocalWorktree {
 
         cx.spawn(|this, _cx| async move {
             let abs_path = abs_path?;
-            let text = fs.load(&abs_path).await?;
+            let text = if skip_file_contents {
+                String::new()
+            } else {
+                fs.load(&abs_path).await?
+            };
 
             let worktree = this
                 .upgrade()

crates/worktree/src/worktree_tests.rs 🔗

@@ -467,7 +467,7 @@ async fn test_open_gitignored_files(cx: &mut TestAppContext) {
     let prev_read_dir_count = fs.read_dir_call_count();
     let loaded = tree
         .update(cx, |tree, cx| {
-            tree.load_file("one/node_modules/b/b1.js".as_ref(), cx)
+            tree.load_file("one/node_modules/b/b1.js".as_ref(), false, cx)
         })
         .await
         .unwrap();
@@ -507,7 +507,7 @@ async fn test_open_gitignored_files(cx: &mut TestAppContext) {
     let prev_read_dir_count = fs.read_dir_call_count();
     let loaded = tree
         .update(cx, |tree, cx| {
-            tree.load_file("one/node_modules/a/a2.js".as_ref(), cx)
+            tree.load_file("one/node_modules/a/a2.js".as_ref(), false, cx)
         })
         .await
         .unwrap();

crates/zed/src/zed.rs 🔗

@@ -404,7 +404,7 @@ fn initialize_panels(
             workspace.add_panel(chat_panel, window, cx);
             workspace.add_panel(notification_panel, window, cx);
             cx.when_flag_enabled::<GitUiFeatureFlag>(window, |workspace, window, cx| {
-                let git_panel = git_ui::git_panel::GitPanel::new(workspace, window, None, cx);
+                let git_panel = git_ui::git_panel::GitPanel::new(workspace, window, cx);
                 workspace.add_panel(git_panel, window, cx);
             });
         })?;