diff --git a/crates/project/src/buffer_store.rs b/crates/project/src/buffer_store.rs index c31f1bfbe5..815ba19ea9 100644 --- a/crates/project/src/buffer_store.rs +++ b/crates/project/src/buffer_store.rs @@ -36,6 +36,7 @@ pub struct BufferStore { loading_buffers: HashMap, Arc>>>>, worktree_store: Entity, opened_buffers: HashMap, + path_to_buffer_id: HashMap, downstream_client: Option<(AnyProtoClient, u64)>, shared_buffers: HashMap>, } @@ -62,7 +63,6 @@ struct RemoteBufferStore { } struct LocalBufferStore { - local_buffer_ids_by_path: HashMap, local_buffer_ids_by_entry_id: HashMap, worktree_store: Entity, _subscription: Subscription, @@ -368,8 +368,9 @@ impl LocalBufferStore { let line_ending = buffer.line_ending(); let version = buffer.version(); let buffer_id = buffer.remote_id(); - if buffer - .file() + let file = buffer.file().cloned(); + if file + .as_ref() .is_some_and(|file| file.disk_state() == DiskState::New) { has_changed_file = true; @@ -462,13 +463,11 @@ impl LocalBufferStore { path: path.clone(), }; - let buffer_id = { - let local = this.as_local_mut()?; - match local.local_buffer_ids_by_entry_id.get(&entry_id) { - Some(&buffer_id) => buffer_id, - None => local.local_buffer_ids_by_path.get(&project_path).copied()?, - } - }; + let buffer_id = this + .as_local_mut() + .and_then(|local| local.local_buffer_ids_by_entry_id.get(&entry_id)) + .copied() + .or_else(|| this.path_to_buffer_id.get(&project_path).copied())?; let buffer = if let Some(buffer) = this.get(buffer_id) { Some(buffer) @@ -480,14 +479,13 @@ impl LocalBufferStore { let buffer = if let Some(buffer) = buffer { buffer } else { + this.path_to_buffer_id.remove(&project_path); let this = this.as_local_mut()?; - this.local_buffer_ids_by_path.remove(&project_path); this.local_buffer_ids_by_entry_id.remove(&entry_id); return None; }; let events = buffer.update(cx, |buffer, cx| { - let local = this.as_local_mut()?; let file = buffer.file()?; let old_file = File::from_dyn(Some(file))?; if old_file.worktree != *worktree { @@ -528,11 +526,11 @@ impl LocalBufferStore { let mut events = Vec::new(); if new_file.path != old_file.path { - local.local_buffer_ids_by_path.remove(&ProjectPath { + this.path_to_buffer_id.remove(&ProjectPath { path: old_file.path.clone(), worktree_id: old_file.worktree_id(cx), }); - local.local_buffer_ids_by_path.insert( + this.path_to_buffer_id.insert( ProjectPath { worktree_id: new_file.worktree_id(cx), path: new_file.path.clone(), @@ -544,7 +542,7 @@ impl LocalBufferStore { old_file: buffer.file().cloned(), }); } - + let local = this.as_local_mut()?; if new_file.entry_id != old_file.entry_id { if let Some(entry_id) = old_file.entry_id { local.local_buffer_ids_by_entry_id.remove(&entry_id); @@ -577,32 +575,6 @@ impl LocalBufferStore { None } - fn buffer_changed_file(&mut self, buffer: Entity, cx: &mut App) -> Option<()> { - let file = File::from_dyn(buffer.read(cx).file())?; - - let remote_id = buffer.read(cx).remote_id(); - if let Some(entry_id) = file.entry_id { - match self.local_buffer_ids_by_entry_id.get(&entry_id) { - Some(_) => { - return None; - } - None => { - self.local_buffer_ids_by_entry_id - .insert(entry_id, remote_id); - } - } - }; - self.local_buffer_ids_by_path.insert( - ProjectPath { - worktree_id: file.worktree_id(cx), - path: file.path.clone(), - }, - remote_id, - ); - - Some(()) - } - fn save_buffer( &self, buffer: Entity, @@ -677,15 +649,14 @@ impl LocalBufferStore { this.add_buffer(buffer.clone(), cx)?; let buffer_id = buffer.read(cx).remote_id(); if let Some(file) = File::from_dyn(buffer.read(cx).file()) { - let this = this.as_local_mut().unwrap(); - this.local_buffer_ids_by_path.insert( + this.path_to_buffer_id.insert( ProjectPath { worktree_id: file.worktree_id(cx), path: file.path.clone(), }, buffer_id, ); - + let this = this.as_local_mut().unwrap(); if let Some(entry_id) = file.entry_id { this.local_buffer_ids_by_entry_id .insert(entry_id, buffer_id); @@ -748,7 +719,6 @@ impl BufferStore { pub fn local(worktree_store: Entity, cx: &mut Context) -> Self { Self { state: BufferStoreState::Local(LocalBufferStore { - local_buffer_ids_by_path: Default::default(), local_buffer_ids_by_entry_id: Default::default(), worktree_store: worktree_store.clone(), _subscription: cx.subscribe(&worktree_store, |this, _, event, cx| { @@ -760,6 +730,7 @@ impl BufferStore { }), downstream_client: None, opened_buffers: Default::default(), + path_to_buffer_id: Default::default(), shared_buffers: Default::default(), loading_buffers: Default::default(), worktree_store, @@ -783,19 +754,13 @@ impl BufferStore { }), downstream_client: None, opened_buffers: Default::default(), + path_to_buffer_id: Default::default(), loading_buffers: Default::default(), shared_buffers: Default::default(), worktree_store, } } - fn as_local(&self) -> Option<&LocalBufferStore> { - match &self.state { - BufferStoreState::Local(state) => Some(state), - _ => None, - } - } - fn as_local_mut(&mut self) -> Option<&mut LocalBufferStore> { match &mut self.state { BufferStoreState::Local(state) => Some(state), @@ -915,6 +880,10 @@ impl BufferStore { fn add_buffer(&mut self, buffer_entity: Entity, cx: &mut Context) -> Result<()> { let buffer = buffer_entity.read(cx); let remote_id = buffer.remote_id(); + let path = File::from_dyn(buffer.file()).map(|file| ProjectPath { + path: file.path.clone(), + worktree_id: file.worktree_id(cx), + }); let is_remote = buffer.replica_id() != 0; let open_buffer = OpenBuffer::Complete { buffer: buffer_entity.downgrade(), @@ -931,10 +900,11 @@ impl BufferStore { }) .detach() }); - + let _expect_path_to_exist; match self.opened_buffers.entry(remote_id) { hash_map::Entry::Vacant(entry) => { entry.insert(open_buffer); + _expect_path_to_exist = false; } hash_map::Entry::Occupied(mut entry) => { if let OpenBuffer::Operations(operations) = entry.get_mut() { @@ -948,9 +918,14 @@ impl BufferStore { } } entry.insert(open_buffer); + _expect_path_to_exist = true; } } + if let Some(path) = path { + self.path_to_buffer_id.insert(path, remote_id); + } + cx.subscribe(&buffer_entity, Self::on_buffer_event).detach(); cx.emit(BufferStoreEvent::BufferAdded(buffer_entity)); Ok(()) @@ -972,18 +947,13 @@ impl BufferStore { } pub fn buffer_id_for_project_path(&self, project_path: &ProjectPath) -> Option<&BufferId> { - self.as_local() - .and_then(|state| state.local_buffer_ids_by_path.get(project_path)) + self.path_to_buffer_id.get(project_path) } - pub fn get_by_path(&self, path: &ProjectPath, cx: &App) -> Option> { - self.buffers().find_map(|buffer| { - let file = File::from_dyn(buffer.read(cx).file())?; - if file.worktree_id(cx) == path.worktree_id && file.path == path.path { - Some(buffer) - } else { - None - } + pub fn get_by_path(&self, path: &ProjectPath, _cx: &App) -> Option> { + self.path_to_buffer_id.get(path).and_then(|buffer_id| { + let buffer = self.get(*buffer_id); + buffer }) } @@ -1055,6 +1025,35 @@ impl BufferStore { .retain(|_, buffer| !matches!(buffer, OpenBuffer::Operations(_))); } + fn buffer_changed_file(&mut self, buffer: Entity, cx: &mut App) -> Option<()> { + let file = File::from_dyn(buffer.read(cx).file())?; + + let remote_id = buffer.read(cx).remote_id(); + if let Some(entry_id) = file.entry_id { + if let Some(local) = self.as_local_mut() { + match local.local_buffer_ids_by_entry_id.get(&entry_id) { + Some(_) => { + return None; + } + None => { + local + .local_buffer_ids_by_entry_id + .insert(entry_id, remote_id); + } + } + } + self.path_to_buffer_id.insert( + ProjectPath { + worktree_id: file.worktree_id(cx), + path: file.path.clone(), + }, + remote_id, + ); + }; + + Some(()) + } + pub fn find_search_candidates( &mut self, query: &SearchQuery, @@ -1118,9 +1117,7 @@ impl BufferStore { ) { match event { BufferEvent::FileHandleChanged => { - if let Some(local) = self.as_local_mut() { - local.buffer_changed_file(buffer, cx); - } + self.buffer_changed_file(buffer, cx); } BufferEvent::Reloaded => { let Some((downstream_client, project_id)) = self.downstream_client.as_ref() else { @@ -1316,6 +1313,7 @@ impl BufferStore { let old_file = buffer.update(cx, |buffer, cx| { let old_file = buffer.file().cloned(); let new_path = file.path.clone(); + buffer.file_updated(Arc::new(file), cx); if old_file .as_ref() @@ -1606,18 +1604,17 @@ impl BufferStore { self.add_buffer(buffer.clone(), cx).log_err(); let buffer_id = buffer.read(cx).remote_id(); - let this = self - .as_local_mut() - .expect("local-only method called in a non-local context"); if let Some(file) = File::from_dyn(buffer.read(cx).file()) { - this.local_buffer_ids_by_path.insert( + self.path_to_buffer_id.insert( ProjectPath { worktree_id: file.worktree_id(cx), path: file.path.clone(), }, buffer_id, ); - + let this = self + .as_local_mut() + .expect("local-only method called in a non-local context"); if let Some(entry_id) = file.entry_id { this.local_buffer_ids_by_entry_id .insert(entry_id, buffer_id);