From 47713d1edba5134ef4e8e112e1b238df9623752e Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 9 Jul 2025 06:31:23 -0600 Subject: [PATCH] WIP --- crates/buffer_diff/src/buffer_diff.rs | 9 ++-- crates/channel/src/channel_store.rs | 3 +- crates/gpui/src/app/entity_map.rs | 9 ++-- crates/gpui/src/app/test_context.rs | 3 +- crates/gpui/src/window.rs | 19 +++++--- crates/language/src/buffer.rs | 11 +++-- crates/language_model/src/registry.rs | 4 +- crates/multi_buffer/src/multi_buffer.rs | 64 +++++++++++++------------ crates/project/src/buffer_store.rs | 6 ++- crates/project/src/project.rs | 3 +- crates/project/src/project_tests.rs | 34 ++++++------- crates/project/src/task_inventory.rs | 2 +- crates/web_search/src/web_search.rs | 4 +- crates/worktree/src/worktree.rs | 36 +++++++------- 14 files changed, 118 insertions(+), 89 deletions(-) diff --git a/crates/buffer_diff/src/buffer_diff.rs b/crates/buffer_diff/src/buffer_diff.rs index ee09fda46e008c903120eb0430ff18fae57dc3da..ce9bda62b4b8e378c7c6fd8f523c09140aea45a8 100644 --- a/crates/buffer_diff/src/buffer_diff.rs +++ b/crates/buffer_diff/src/buffer_diff.rs @@ -4,6 +4,7 @@ use gpui::{App, AppContext as _, AsyncApp, Context, Entity, EventEmitter, Task, use language::{Language, LanguageRegistry}; use rope::Rope; use std::{ + cell::Ref, cmp::Ordering, future::Future, iter, @@ -1109,9 +1110,11 @@ impl BufferDiff { let unstaged_counterpart = self .secondary_diff .as_ref() - .map(|diff| &diff.read(cx).inner); - self.inner - .hunks_intersecting_range(range, buffer_snapshot, unstaged_counterpart) + .map(|diff| Ref::map(diff.read(cx), |d| &d.inner)); + // self.inner + // .hunks_intersecting_range(range, buffer_snapshot, unstaged_counterpart) + // todo! Figure out what to do here + None.into_iter() } pub fn hunks_intersecting_range_rev<'a>( diff --git a/crates/channel/src/channel_store.rs b/crates/channel/src/channel_store.rs index b7ba811421d63be6d288606eb2e7d2fa1199f983..42da573db858a101dfb77e9f63501030453f3e82 100644 --- a/crates/channel/src/channel_store.rs +++ b/crates/channel/src/channel_store.rs @@ -976,7 +976,8 @@ impl ChannelStore { if let OpenEntityHandle::Open(buffer) = buffer { if let Some(buffer) = buffer.upgrade() { let channel_buffer = buffer.read(cx); - let buffer = channel_buffer.buffer().read(cx); + let buffer = channel_buffer.buffer(); + let buffer = buffer.read(cx); buffer_versions.push(proto::ChannelBufferVersion { channel_id: channel_buffer.channel_id.0, epoch: channel_buffer.epoch(), diff --git a/crates/gpui/src/app/entity_map.rs b/crates/gpui/src/app/entity_map.rs index a45f7de7bea5e9c30cdaecfa2c013ac58ef9798a..1a2bca869c1c11769c20952fc84ecb88dfd7422a 100644 --- a/crates/gpui/src/app/entity_map.rs +++ b/crates/gpui/src/app/entity_map.rs @@ -6,7 +6,7 @@ use parking_lot::{RwLock, RwLockUpgradableReadGuard}; use slotmap::{KeyData, SecondaryMap, SlotMap}; use std::{ any::{Any, TypeId, type_name}, - cell::RefCell, + cell::{Ref, RefCell}, cmp::Ordering, fmt::{self, Display}, hash::{Hash, Hasher}, @@ -371,8 +371,11 @@ impl Entity { } /// Grab a reference to this entity from the context. - pub fn read<'a>(&self, cx: &'a App) -> &'a T { - cx.entities.read(self) + /// todo! remove the cx param + pub fn read(&self, _cx: &App) -> Ref { + Ref::map(self.any_entity.entity_data.borrow(), |data| { + data.downcast_ref().unwrap() + }) } /// Read the entity referenced by this handle with the given function. diff --git a/crates/gpui/src/app/test_context.rs b/crates/gpui/src/app/test_context.rs index 07784198ae3844bac744713221f76679ec02f598..a803cc21277af7779ce0a3c744e1778c5005c730 100644 --- a/crates/gpui/src/app/test_context.rs +++ b/crates/gpui/src/app/test_context.rs @@ -624,7 +624,8 @@ impl Entity { handle .upgrade() .expect("view dropped with pending condition") - .read(cx), + .read(cx) + .deref(), cx, ) { break; diff --git a/crates/gpui/src/window.rs b/crates/gpui/src/window.rs index 8c01b8afcfd2b7948cabe925550008590b3c3576..85d81fb57bd9bc68a9bcaf0f599fe86d79fc86be 100644 --- a/crates/gpui/src/window.rs +++ b/crates/gpui/src/window.rs @@ -31,6 +31,8 @@ use raw_window_handle::{HandleError, HasDisplayHandle, HasWindowHandle}; use refineable::Refineable; use slotmap::SlotMap; use smallvec::SmallVec; +use std::cell::Ref; +use std::ops::Deref; use std::{ any::{Any, TypeId}, borrow::Cow, @@ -4139,7 +4141,8 @@ impl Window { if let Some(inspector_id) = _inspector_id { if let Some(inspector) = &self.inspector { let inspector = inspector.clone(); - let active_element_id = inspector.read(cx).active_element_id(); + let inspector_ref = inspector.read(cx); + let active_element_id = inspector_ref.active_element_id(); if Some(inspector_id) == active_element_id { return inspector.update(cx, |inspector, _cx| { inspector.with_active_element_state(self, f) @@ -4213,9 +4216,9 @@ impl Window { #[cfg(any(feature = "inspector", debug_assertions))] fn paint_inspector_hitbox(&mut self, cx: &App) { - if let Some(inspector) = self.inspector.as_ref() { - let inspector = inspector.read(cx); - if let Some((hitbox_id, _)) = self.hovered_inspector_hitbox(inspector, &self.next_frame) + if let Some(inspector) = self.inspector.clone() { + if let Some((hitbox_id, _)) = + self.hovered_inspector_hitbox(inspector.read(cx).deref(), &self.next_frame) { if let Some(hitbox) = self .next_frame @@ -4379,7 +4382,7 @@ impl WindowHandle { /// Read the root view out of this window. /// /// This will fail if the window is closed or if the root view's type does not match `V`. - pub fn read<'a>(&self, cx: &'a App) -> Result<&'a V> { + pub fn read(&self, cx: &App) -> Result> { let x = cx .windows .get(self.id) @@ -4392,7 +4395,7 @@ impl WindowHandle { .context("window not found")? .map_err(|_| anyhow!("the type of the window's root view has changed"))?; - Ok(x.read(cx)) + todo!() } /// Read the root view out of this window, with a callback @@ -4402,7 +4405,9 @@ impl WindowHandle { where C: AppContext, { - cx.read_window(self, |root_view, cx| read_with(root_view.read(cx), cx)) + cx.read_window(self, |root_view, cx| { + read_with(root_view.read(cx).deref(), cx) + }) } /// Read the root view pointer off of this window. diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 891e1f4dea81ffc2bc947fe80e18dfeb45ea793b..a84206dc629c7c9df1b244500082f78699725f51 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -41,7 +41,7 @@ use std::{ cell::Cell, cmp::{self, Ordering, Reverse}, collections::{BTreeMap, BTreeSet}, - ffi::OsStr, + ffi::{OsStr, OsString}, future::Future, iter::{self, Iterator, Peekable}, mem, @@ -343,7 +343,7 @@ pub trait File: Send + Sync + Any { /// Returns the last component of this handle's absolute path. If this handle refers to the root /// of its worktree, then this method will return the name of the worktree itself. - fn file_name<'a>(&'a self, cx: &'a App) -> &'a OsStr; + fn file_name<'a>(&'a self, cx: &'a App) -> OsString; /// Returns the id of the worktree to which this file belongs. /// @@ -4895,8 +4895,11 @@ impl File for TestFile { unimplemented!() } - fn file_name<'a>(&'a self, _: &'a gpui::App) -> &'a std::ffi::OsStr { - self.path().file_name().unwrap_or(self.root_name.as_ref()) + fn file_name<'a>(&'a self, _: &'a gpui::App) -> OsString { + self.path() + .file_name() + .unwrap_or(self.root_name.as_ref()) + .into() } fn worktree_id(&self, _: &App) -> WorktreeId { diff --git a/crates/language_model/src/registry.rs b/crates/language_model/src/registry.rs index 840fda38dec4714a32f3397a28dd2d116bb67f5d..25bc9acc8a3b725da5752e289168e16da9443cfe 100644 --- a/crates/language_model/src/registry.rs +++ b/crates/language_model/src/registry.rs @@ -4,7 +4,7 @@ use crate::{ }; use collections::BTreeMap; use gpui::{App, Context, Entity, EventEmitter, Global, prelude::*}; -use std::{str::FromStr, sync::Arc}; +use std::{cell::Ref, str::FromStr, sync::Arc}; use thiserror::Error; use util::maybe; @@ -119,7 +119,7 @@ impl LanguageModelRegistry { cx.global::().0.clone() } - pub fn read_global(cx: &App) -> &Self { + pub fn read_global(cx: &App) -> Ref { cx.global::().0.read(cx) } diff --git a/crates/multi_buffer/src/multi_buffer.rs b/crates/multi_buffer/src/multi_buffer.rs index e22fdb1ed5a978211d4dc6fd071107600ccf789f..234530746295f57a88a4e410d1a7b5582c322500 100644 --- a/crates/multi_buffer/src/multi_buffer.rs +++ b/crates/multi_buffer/src/multi_buffer.rs @@ -1215,8 +1215,9 @@ impl MultiBuffer { if let Some(excerpt) = cursor.item() { if excerpt.locator == *excerpt_id { let excerpt_buffer_start = - excerpt.range.context.start.summary::(buffer); - let excerpt_buffer_end = excerpt.range.context.end.summary::(buffer); + excerpt.range.context.start.summary::(&buffer); + let excerpt_buffer_end = + excerpt.range.context.end.summary::(&buffer); let excerpt_range = excerpt_buffer_start..excerpt_buffer_end; if excerpt_range.contains(&range.start) && excerpt_range.contains(&range.end) @@ -2477,7 +2478,7 @@ impl MultiBuffer { }; let buffer = buffer_state.buffer.read(cx); - let diff_change_range = range.to_offset(buffer); + let diff_change_range = range.to_offset(&buffer); let new_diff = diff.snapshot(cx); let mut snapshot = self.snapshot.borrow_mut(); @@ -2558,19 +2559,20 @@ impl MultiBuffer { } pub fn language_settings<'a>(&'a self, cx: &'a App) -> Cow<'a, LanguageSettings> { - let buffer_id = self - .snapshot - .borrow() - .excerpts - .first() - .map(|excerpt| excerpt.buffer.remote_id()); - buffer_id - .and_then(|buffer_id| self.buffer(buffer_id)) - .map(|buffer| { - let buffer = buffer.read(cx); - language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx) - }) - .unwrap_or_else(move || self.language_settings_at(0, cx)) + // let buffer_id = self + // .snapshot + // .borrow() + // .excerpts + // .first() + // .map(|excerpt| excerpt.buffer.remote_id()); + // buffer_id + // .and_then(|buffer_id| self.buffer(buffer_id)) + // .map(|buffer| { + // let buffer = buffer.read(cx); + // language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx) + // }) + // .unwrap_or_else(move || self.language_settings_at(0, cx)) + todo!() } pub fn language_settings_at<'a, T: ToOffset>( @@ -2585,7 +2587,8 @@ impl MultiBuffer { language = buffer.language_at(offset); file = buffer.file(); } - language_settings(language.map(|l| l.name()), file, cx) + // language_settings(language.map(|l| l.name()), file, cx) + todo!() } pub fn for_each_buffer(&self, mut f: impl FnMut(&Entity)) { @@ -2596,23 +2599,24 @@ impl MultiBuffer { } pub fn title<'a>(&'a self, cx: &'a App) -> Cow<'a, str> { - if let Some(title) = self.title.as_ref() { - return title.into(); - } + // if let Some(title) = self.title.as_ref() { + // return title.into(); + // } - if let Some(buffer) = self.as_singleton() { - let buffer = buffer.read(cx); + // if let Some(buffer) = self.as_singleton() { + // let buffer = buffer.read(cx); - if let Some(file) = buffer.file() { - return file.file_name(cx).to_string_lossy(); - } + // if let Some(file) = buffer.file() { + // return file.file_name(cx).to_string_lossy(); + // } - if let Some(title) = self.buffer_content_title(buffer) { - return title; - } - }; + // if let Some(title) = self.buffer_content_title(&buffer) { + // return title; + // } + // }; - "untitled".into() + // "untitled".into() + todo!() } fn buffer_content_title(&self, buffer: &Buffer) -> Option> { diff --git a/crates/project/src/buffer_store.rs b/crates/project/src/buffer_store.rs index 1c902a7aee79700b0f922ea2d04ba86641b87259..44ebd13011d4de06ab4be185fdfff44162902883 100644 --- a/crates/project/src/buffer_store.rs +++ b/crates/project/src/buffer_store.rs @@ -126,6 +126,7 @@ impl RemoteBufferStore { let version = buffer.version(); let rpc = self.upstream_client.clone(); let project_id = self.project_id; + drop(buffer); cx.spawn(async move |_, cx| { let response = rpc .request(proto::SaveBuffer { @@ -373,6 +374,7 @@ impl LocalBufferStore { let save = worktree.update(cx, |worktree, cx| { worktree.write_file(path.as_ref(), text, line_ending, cx) }); + drop(buffer); cx.spawn(async move |this, cx| { let new_file = save.await?; @@ -574,7 +576,8 @@ impl LocalBufferStore { buffer: Entity, cx: &mut Context, ) -> Task> { - let Some(file) = File::from_dyn(buffer.read(cx).file()) else { + let buffer_ref = buffer.read(cx); + let Some(file) = File::from_dyn(buffer_ref.file()) else { return Task::ready(Err(anyhow!("buffer doesn't have a file"))); }; let worktree = file.worktree.clone(); @@ -922,6 +925,7 @@ impl BufferStore { self.path_to_buffer_id.insert(path, remote_id); } + drop(buffer); cx.subscribe(&buffer_entity, Self::on_buffer_event).detach(); cx.emit(BufferStoreEvent::BufferAdded(buffer_entity)); Ok(()) diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 8e1026421e984b77655d451a2b80f1fe1299ebfb..083949500fd614c1293038a692510d34143e4aa8 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -1740,7 +1740,8 @@ impl Project { } pub fn active_debug_session(&self, cx: &App) -> Option<(Entity, ActiveStackFrame)> { - let active_position = self.breakpoint_store.read(cx).active_position()?; + let store = self.breakpoint_store.read(cx); + let active_position = store.active_position()?; let session = self .dap_store .read(cx) diff --git a/crates/project/src/project_tests.rs b/crates/project/src/project_tests.rs index 779cf95add9ad5547e13d85d87c0dcc3935ab326..2ff4863e6a37e2a8bb15488f103467a0ec213b05 100644 --- a/crates/project/src/project_tests.rs +++ b/crates/project/src/project_tests.rs @@ -8162,8 +8162,8 @@ async fn test_update_gitignore(cx: &mut gpui::TestAppContext) { // One file is unmodified, the other is ignored. cx.read(|cx| { - assert_entry_git_state(tree.read(cx), repository.read(cx), "a.xml", None, false); - assert_entry_git_state(tree.read(cx), repository.read(cx), "b.txt", None, true); + assert_entry_git_state(&tree.read(cx), &repository.read(cx), "a.xml", None, false); + assert_entry_git_state(&tree.read(cx), &repository.read(cx), "b.txt", None, true); }); // Change the gitignore, and stage the newly non-ignored file. @@ -8181,10 +8181,10 @@ async fn test_update_gitignore(cx: &mut gpui::TestAppContext) { cx.executor().run_until_parked(); cx.read(|cx| { - assert_entry_git_state(tree.read(cx), repository.read(cx), "a.xml", None, true); + assert_entry_git_state(&tree.read(cx), &repository.read(cx), "a.xml", None, true); assert_entry_git_state( - tree.read(cx), - repository.read(cx), + &tree.read(cx), + &repository.read(cx), "b.txt", Some(StatusCode::Added), false, @@ -8597,22 +8597,22 @@ async fn test_rescan_with_gitignore(cx: &mut gpui::TestAppContext) { cx.read(|cx| { assert_entry_git_state( - tree.read(cx), - repository.read(cx), + &tree.read(cx), + &repository.read(cx), "tracked-dir/tracked-file1", None, false, ); assert_entry_git_state( - tree.read(cx), - repository.read(cx), + &tree.read(cx), + &repository.read(cx), "tracked-dir/ancestor-ignored-file1", None, false, ); assert_entry_git_state( - tree.read(cx), - repository.read(cx), + &tree.read(cx), + &repository.read(cx), "ignored-dir/ignored-file1", None, true, @@ -8649,22 +8649,22 @@ async fn test_rescan_with_gitignore(cx: &mut gpui::TestAppContext) { cx.executor().run_until_parked(); cx.read(|cx| { assert_entry_git_state( - tree.read(cx), - repository.read(cx), + &tree.read(cx), + &repository.read(cx), "tracked-dir/tracked-file2", Some(StatusCode::Added), false, ); assert_entry_git_state( - tree.read(cx), - repository.read(cx), + &tree.read(cx), + &repository.read(cx), "tracked-dir/ancestor-ignored-file2", None, false, ); assert_entry_git_state( - tree.read(cx), - repository.read(cx), + &tree.read(cx), + &repository.read(cx), "ignored-dir/ignored-file2", None, true, diff --git a/crates/project/src/task_inventory.rs b/crates/project/src/task_inventory.rs index d0f1c71daf797681d08a741ea15ab28f4a9289a0..22efd52cbe8ba43aab3ac504bbb49d3a08350592 100644 --- a/crates/project/src/task_inventory.rs +++ b/crates/project/src/task_inventory.rs @@ -435,7 +435,7 @@ impl Inventory { let fs = self.fs.clone(); let worktree = task_contexts.worktree(); let location = task_contexts.location(); - let language = location.and_then(|location| location.buffer.read(cx).language()); + let language = location.and_then(|location| location.buffer.read(cx).language().clone()); let task_source_kind = language.as_ref().map(|language| TaskSourceKind::Language { name: language.name().into(), }); diff --git a/crates/web_search/src/web_search.rs b/crates/web_search/src/web_search.rs index a131b0de7166709679a8ebc8e7d64af35118eb22..36f2a7c5c14a992e4b1602afdd02acb03bf34a17 100644 --- a/crates/web_search/src/web_search.rs +++ b/crates/web_search/src/web_search.rs @@ -1,7 +1,7 @@ use anyhow::Result; use collections::HashMap; use gpui::{App, AppContext as _, Context, Entity, Global, SharedString, Task}; -use std::sync::Arc; +use std::{cell::Ref, sync::Arc}; use zed_llm_client::WebSearchResponse; pub fn init(cx: &mut App) { @@ -32,7 +32,7 @@ impl WebSearchRegistry { cx.global::().0.clone() } - pub fn read_global(cx: &App) -> &Self { + pub fn read_global(cx: &App) -> Ref { cx.global::().0.read(cx) } diff --git a/crates/worktree/src/worktree.rs b/crates/worktree/src/worktree.rs index 8c407fdd3eab5a6b7189f67ff46b8ce76d1a428d..96269e10bd108ab80a5bec61822967cb57dbc49c 100644 --- a/crates/worktree/src/worktree.rs +++ b/crates/worktree/src/worktree.rs @@ -49,7 +49,7 @@ use std::{ cmp::Ordering, collections::hash_map, convert::TryFrom, - ffi::OsStr, + ffi::{OsStr, OsString}, fmt, future::Future, mem::{self}, @@ -2667,17 +2667,18 @@ impl Snapshot { } pub fn entry_for_path(&self, path: impl AsRef) -> Option<&Entry> { - let path = path.as_ref(); - debug_assert!(path.is_relative()); - self.traverse_from_path(true, true, true, path) - .entry() - .and_then(|entry| { - if entry.path.as_ref() == path { - Some(entry) - } else { - None - } - }) + // let path = path.as_ref(); + // debug_assert!(path.is_relative()); + // self.traverse_from_path(true, true, true, path) + // .entry() + // .and_then(|entry| { + // if entry.path.as_ref() == path { + // Some(entry) + // } else { + // None + // } + // }) + todo!() } pub fn entry_for_id(&self, id: ProjectEntryId) -> Option<&Entry> { @@ -3321,10 +3322,11 @@ impl language::File for File { /// Returns the last component of this handle's absolute path. If this handle refers to the root /// of its worktree, then this method will return the name of the worktree itself. - fn file_name<'a>(&'a self, cx: &'a App) -> &'a OsStr { + fn file_name<'a>(&'a self, cx: &'a App) -> OsString { self.path .file_name() - .unwrap_or_else(|| OsStr::new(&self.worktree.read(cx).root_name)) + .map(Into::into) + .unwrap_or_else(|| OsStr::new(&self.worktree.read(cx).root_name).into()) } fn worktree_id(&self, cx: &App) -> WorktreeId { @@ -3357,14 +3359,16 @@ impl language::LocalFile for File { } fn load(&self, cx: &App) -> Task> { - let worktree = self.worktree.read(cx).as_local().unwrap(); + let worktree = self.worktree.read(cx); + let worktree = worktree.as_local().unwrap(); let abs_path = worktree.absolutize(&self.path); let fs = worktree.fs.clone(); cx.background_spawn(async move { fs.load(&abs_path?).await }) } fn load_bytes(&self, cx: &App) -> Task>> { - let worktree = self.worktree.read(cx).as_local().unwrap(); + let worktree = self.worktree.read(cx); + let worktree = worktree.as_local().unwrap(); let abs_path = worktree.absolutize(&self.path); let fs = worktree.fs.clone(); cx.background_spawn(async move { fs.load_bytes(&abs_path?).await })