Compare commits
4 commits
main
...
refcell-en
Author | SHA1 | Date | |
---|---|---|---|
![]() |
a9ffad9e7f | ||
![]() |
47713d1edb | ||
![]() |
1eea7400e5 | ||
![]() |
6256e80933 |
32 changed files with 690 additions and 543 deletions
|
@ -4,6 +4,7 @@ use gpui::{App, AppContext as _, AsyncApp, Context, Entity, EventEmitter, Task,
|
||||||
use language::{Language, LanguageRegistry};
|
use language::{Language, LanguageRegistry};
|
||||||
use rope::Rope;
|
use rope::Rope;
|
||||||
use std::{
|
use std::{
|
||||||
|
cell::Ref,
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
future::Future,
|
future::Future,
|
||||||
iter,
|
iter,
|
||||||
|
@ -1109,9 +1110,11 @@ impl BufferDiff {
|
||||||
let unstaged_counterpart = self
|
let unstaged_counterpart = self
|
||||||
.secondary_diff
|
.secondary_diff
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|diff| &diff.read(cx).inner);
|
.map(|diff| Ref::map(diff.read(cx), |d| &d.inner));
|
||||||
self.inner
|
// self.inner
|
||||||
.hunks_intersecting_range(range, buffer_snapshot, unstaged_counterpart)
|
// .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>(
|
pub fn hunks_intersecting_range_rev<'a>(
|
||||||
|
|
|
@ -976,7 +976,8 @@ impl ChannelStore {
|
||||||
if let OpenEntityHandle::Open(buffer) = buffer {
|
if let OpenEntityHandle::Open(buffer) = buffer {
|
||||||
if let Some(buffer) = buffer.upgrade() {
|
if let Some(buffer) = buffer.upgrade() {
|
||||||
let channel_buffer = buffer.read(cx);
|
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 {
|
buffer_versions.push(proto::ChannelBufferVersion {
|
||||||
channel_id: channel_buffer.channel_id.0,
|
channel_id: channel_buffer.channel_id.0,
|
||||||
epoch: channel_buffer.epoch(),
|
epoch: channel_buffer.epoch(),
|
||||||
|
|
|
@ -17,7 +17,7 @@ use async_trait::async_trait;
|
||||||
use buffer_diff::DiffHunkStatus;
|
use buffer_diff::DiffHunkStatus;
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use futures::{FutureExt as _, StreamExt, channel::mpsc, select_biased};
|
use futures::{FutureExt as _, StreamExt, channel::mpsc, select_biased};
|
||||||
use gpui::{App, AppContext, AsyncApp, Entity};
|
use gpui::{App, AppContext, AsyncApp, Entity, EntityId};
|
||||||
use language_model::{LanguageModel, Role, StopReason};
|
use language_model::{LanguageModel, Role, StopReason};
|
||||||
use zed_llm_client::CompletionIntent;
|
use zed_llm_client::CompletionIntent;
|
||||||
|
|
||||||
|
@ -402,16 +402,16 @@ impl AppContext for ExampleContext {
|
||||||
self.app.new(build_entity)
|
self.app.new(build_entity)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reserve_entity<T: 'static>(&mut self) -> Self::Result<gpui::Reservation<T>> {
|
fn reserve_entity(&mut self) -> Self::Result<EntityId> {
|
||||||
self.app.reserve_entity()
|
self.app.reserve_entity()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_entity<T: 'static>(
|
fn insert_entity<T: 'static>(
|
||||||
&mut self,
|
&mut self,
|
||||||
reservation: gpui::Reservation<T>,
|
entity_id: EntityId,
|
||||||
build_entity: impl FnOnce(&mut gpui::Context<T>) -> T,
|
build_entity: impl FnOnce(&mut gpui::Context<T>) -> T,
|
||||||
) -> Self::Result<Entity<T>> {
|
) -> Self::Result<Entity<T>> {
|
||||||
self.app.insert_entity(reservation, build_entity)
|
self.app.insert_entity(entity_id, build_entity)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_entity<T, R>(
|
fn update_entity<T, R>(
|
||||||
|
|
|
@ -38,9 +38,9 @@ use crate::{
|
||||||
EventEmitter, FocusHandle, FocusMap, ForegroundExecutor, Global, KeyBinding, KeyContext,
|
EventEmitter, FocusHandle, FocusMap, ForegroundExecutor, Global, KeyBinding, KeyContext,
|
||||||
Keymap, Keystroke, LayoutId, Menu, MenuItem, OwnedMenu, PathPromptOptions, Pixels, Platform,
|
Keymap, Keystroke, LayoutId, Menu, MenuItem, OwnedMenu, PathPromptOptions, Pixels, Platform,
|
||||||
PlatformDisplay, PlatformKeyboardLayout, Point, PromptBuilder, PromptButton, PromptHandle,
|
PlatformDisplay, PlatformKeyboardLayout, Point, PromptBuilder, PromptButton, PromptHandle,
|
||||||
PromptLevel, Render, RenderImage, RenderablePromptHandle, Reservation, ScreenCaptureSource,
|
PromptLevel, Render, RenderImage, RenderablePromptHandle, ScreenCaptureSource, SubscriberSet,
|
||||||
SubscriberSet, Subscription, SvgRenderer, Task, TextSystem, Window, WindowAppearance,
|
Subscription, SvgRenderer, Task, TextSystem, Window, WindowAppearance, WindowHandle, WindowId,
|
||||||
WindowHandle, WindowId, WindowInvalidator,
|
WindowInvalidator,
|
||||||
colors::{Colors, GlobalColors},
|
colors::{Colors, GlobalColors},
|
||||||
current_platform, hash, init_app_menus,
|
current_platform, hash, init_app_menus,
|
||||||
};
|
};
|
||||||
|
@ -930,11 +930,11 @@ impl App {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (entity_id, mut entity) in dropped {
|
for (entity_id, entity) in dropped {
|
||||||
self.observers.remove(&entity_id);
|
self.observers.remove(&entity_id);
|
||||||
self.event_listeners.remove(&entity_id);
|
self.event_listeners.remove(&entity_id);
|
||||||
for release_callback in self.release_listeners.remove(&entity_id) {
|
for release_callback in self.release_listeners.remove(&entity_id) {
|
||||||
release_callback(entity.as_mut(), self);
|
release_callback(entity.borrow_mut().deref_mut(), self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1746,9 +1746,9 @@ impl AppContext for App {
|
||||||
/// [`Entity`] handle will be returned, which can be used to access the entity in a context.
|
/// [`Entity`] handle will be returned, which can be used to access the entity in a context.
|
||||||
fn new<T: 'static>(&mut self, build_entity: impl FnOnce(&mut Context<T>) -> T) -> Entity<T> {
|
fn new<T: 'static>(&mut self, build_entity: impl FnOnce(&mut Context<T>) -> T) -> Entity<T> {
|
||||||
self.update(|cx| {
|
self.update(|cx| {
|
||||||
let slot = cx.entities.reserve();
|
let entity_id = cx.entities.reserve();
|
||||||
let handle = slot.clone();
|
let entity = build_entity(&mut Context::new_context(cx, entity_id, None));
|
||||||
let entity = build_entity(&mut Context::new_context(cx, slot.downgrade()));
|
let handle = cx.entities.insert(entity_id, entity);
|
||||||
|
|
||||||
cx.push_effect(Effect::EntityCreated {
|
cx.push_effect(Effect::EntityCreated {
|
||||||
entity: handle.clone().into_any(),
|
entity: handle.clone().into_any(),
|
||||||
|
@ -1756,24 +1756,22 @@ impl AppContext for App {
|
||||||
window: cx.window_update_stack.last().cloned(),
|
window: cx.window_update_stack.last().cloned(),
|
||||||
});
|
});
|
||||||
|
|
||||||
cx.entities.insert(slot, entity);
|
|
||||||
handle
|
handle
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reserve_entity<T: 'static>(&mut self) -> Self::Result<Reservation<T>> {
|
fn reserve_entity(&mut self) -> Self::Result<EntityId> {
|
||||||
Reservation(self.entities.reserve())
|
self.entities.reserve()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_entity<T: 'static>(
|
fn insert_entity<T: 'static>(
|
||||||
&mut self,
|
&mut self,
|
||||||
reservation: Reservation<T>,
|
entity_id: EntityId,
|
||||||
build_entity: impl FnOnce(&mut Context<T>) -> T,
|
build_entity: impl FnOnce(&mut Context<T>) -> T,
|
||||||
) -> Self::Result<Entity<T>> {
|
) -> Self::Result<Entity<T>> {
|
||||||
self.update(|cx| {
|
self.update(|cx| {
|
||||||
let slot = reservation.0;
|
let entity = build_entity(&mut Context::new_context(cx, entity_id, None));
|
||||||
let entity = build_entity(&mut Context::new_context(cx, slot.downgrade()));
|
cx.entities.insert(entity_id, entity)
|
||||||
cx.entities.insert(slot, entity)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1785,13 +1783,11 @@ impl AppContext for App {
|
||||||
update: impl FnOnce(&mut T, &mut Context<T>) -> R,
|
update: impl FnOnce(&mut T, &mut Context<T>) -> R,
|
||||||
) -> R {
|
) -> R {
|
||||||
self.update(|cx| {
|
self.update(|cx| {
|
||||||
let mut entity = cx.entities.lease(handle);
|
let mut entity = cx.entities.get(handle.entity_id());
|
||||||
let result = update(
|
update(
|
||||||
&mut entity,
|
entity.borrow_mut().downcast_mut().unwrap(),
|
||||||
&mut Context::new_context(cx, handle.downgrade()),
|
&mut Context::new_context(cx, handle.entity_id(), Some(handle.downgrade())),
|
||||||
);
|
)
|
||||||
cx.entities.end_lease(entity);
|
|
||||||
result
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
AnyView, AnyWindowHandle, App, AppCell, AppContext, BackgroundExecutor, BorrowAppContext,
|
AnyView, AnyWindowHandle, App, AppCell, AppContext, BackgroundExecutor, BorrowAppContext,
|
||||||
Entity, EventEmitter, Focusable, ForegroundExecutor, Global, PromptButton, PromptLevel, Render,
|
Entity, EntityId, EventEmitter, Focusable, ForegroundExecutor, Global, PromptButton,
|
||||||
Reservation, Result, Subscription, Task, VisualContext, Window, WindowHandle,
|
PromptLevel, Render, Result, Subscription, Task, VisualContext, Window, WindowHandle,
|
||||||
};
|
};
|
||||||
use anyhow::Context as _;
|
use anyhow::Context as _;
|
||||||
use derive_more::{Deref, DerefMut};
|
use derive_more::{Deref, DerefMut};
|
||||||
|
@ -32,7 +32,7 @@ impl AppContext for AsyncApp {
|
||||||
Ok(app.new(build_entity))
|
Ok(app.new(build_entity))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reserve_entity<T: 'static>(&mut self) -> Result<Reservation<T>> {
|
fn reserve_entity(&mut self) -> Result<EntityId> {
|
||||||
let app = self.app.upgrade().context("app was released")?;
|
let app = self.app.upgrade().context("app was released")?;
|
||||||
let mut app = app.borrow_mut();
|
let mut app = app.borrow_mut();
|
||||||
Ok(app.reserve_entity())
|
Ok(app.reserve_entity())
|
||||||
|
@ -40,12 +40,12 @@ impl AppContext for AsyncApp {
|
||||||
|
|
||||||
fn insert_entity<T: 'static>(
|
fn insert_entity<T: 'static>(
|
||||||
&mut self,
|
&mut self,
|
||||||
reservation: Reservation<T>,
|
entity_id: EntityId,
|
||||||
build_entity: impl FnOnce(&mut Context<T>) -> T,
|
build_entity: impl FnOnce(&mut Context<T>) -> T,
|
||||||
) -> Result<Entity<T>> {
|
) -> Result<Entity<T>> {
|
||||||
let app = self.app.upgrade().context("app was released")?;
|
let app = self.app.upgrade().context("app was released")?;
|
||||||
let mut app = app.borrow_mut();
|
let mut app = app.borrow_mut();
|
||||||
Ok(app.insert_entity(reservation, build_entity))
|
Ok(app.insert_entity(entity_id, build_entity))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_entity<T: 'static, R>(
|
fn update_entity<T: 'static, R>(
|
||||||
|
@ -342,17 +342,17 @@ impl AppContext for AsyncWindowContext {
|
||||||
self.window.update(self, |_, _, cx| cx.new(build_entity))
|
self.window.update(self, |_, _, cx| cx.new(build_entity))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reserve_entity<T: 'static>(&mut self) -> Result<Reservation<T>> {
|
fn reserve_entity(&mut self) -> Result<EntityId> {
|
||||||
self.window.update(self, |_, _, cx| cx.reserve_entity())
|
self.window.update(self, |_, _, cx| cx.reserve_entity())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_entity<T: 'static>(
|
fn insert_entity<T: 'static>(
|
||||||
&mut self,
|
&mut self,
|
||||||
reservation: Reservation<T>,
|
entity_id: EntityId,
|
||||||
build_entity: impl FnOnce(&mut Context<T>) -> T,
|
build_entity: impl FnOnce(&mut Context<T>) -> T,
|
||||||
) -> Self::Result<Entity<T>> {
|
) -> Self::Result<Entity<T>> {
|
||||||
self.window
|
self.window
|
||||||
.update(self, |_, _, cx| cx.insert_entity(reservation, build_entity))
|
.update(self, |_, _, cx| cx.insert_entity(entity_id, build_entity))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_entity<T: 'static, R>(
|
fn update_entity<T: 'static, R>(
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
AnyView, AnyWindowHandle, AppContext, AsyncApp, DispatchPhase, Effect, EntityId, EventEmitter,
|
AnyView, AnyWindowHandle, AppContext, AsyncApp, DispatchPhase, Effect, EntityId, EventEmitter,
|
||||||
FocusHandle, FocusOutEvent, Focusable, Global, KeystrokeObserver, Reservation, SubscriberSet,
|
FocusHandle, FocusOutEvent, Focusable, Global, KeystrokeObserver, SubscriberSet, Subscription,
|
||||||
Subscription, Task, WeakEntity, WeakFocusHandle, Window, WindowHandle,
|
Task, WeakEntity, WeakFocusHandle, Window, WindowHandle,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use derive_more::{Deref, DerefMut};
|
use derive_more::{Deref, DerefMut};
|
||||||
|
@ -22,17 +22,26 @@ pub struct Context<'a, T> {
|
||||||
#[deref]
|
#[deref]
|
||||||
#[deref_mut]
|
#[deref_mut]
|
||||||
app: &'a mut App,
|
app: &'a mut App,
|
||||||
entity_state: WeakEntity<T>,
|
entity_id: EntityId,
|
||||||
|
entity_state: Option<WeakEntity<T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: 'static> Context<'a, T> {
|
impl<'a, T: 'static> Context<'a, T> {
|
||||||
pub(crate) fn new_context(app: &'a mut App, entity_state: WeakEntity<T>) -> Self {
|
pub(crate) fn new_context(
|
||||||
Self { app, entity_state }
|
app: &'a mut App,
|
||||||
|
entity_id: EntityId,
|
||||||
|
entity_state: Option<WeakEntity<T>>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
app,
|
||||||
|
entity_id,
|
||||||
|
entity_state,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The entity id of the entity backing this context.
|
/// The entity id of the entity backing this context.
|
||||||
pub fn entity_id(&self) -> EntityId {
|
pub fn entity_id(&self) -> EntityId {
|
||||||
self.entity_state.entity_id
|
self.entity_id
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a handle to the entity belonging to this context.
|
/// Returns a handle to the entity belonging to this context.
|
||||||
|
@ -44,7 +53,7 @@ impl<'a, T: 'static> Context<'a, T> {
|
||||||
|
|
||||||
/// Returns a weak handle to the entity belonging to this context.
|
/// Returns a weak handle to the entity belonging to this context.
|
||||||
pub fn weak_entity(&self) -> WeakEntity<T> {
|
pub fn weak_entity(&self) -> WeakEntity<T> {
|
||||||
self.entity_state.clone()
|
self.entity_state.as_ref().unwrap().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Arranges for the given function to be called whenever [`Context::notify`] is
|
/// Arranges for the given function to be called whenever [`Context::notify`] is
|
||||||
|
@ -112,7 +121,7 @@ impl<'a, T: 'static> Context<'a, T> {
|
||||||
T: 'static,
|
T: 'static,
|
||||||
{
|
{
|
||||||
let (subscription, activate) = self.app.release_listeners.insert(
|
let (subscription, activate) = self.app.release_listeners.insert(
|
||||||
self.entity_state.entity_id,
|
self.entity_id,
|
||||||
Box::new(move |this, cx| {
|
Box::new(move |this, cx| {
|
||||||
let this = this.downcast_mut().expect("invalid entity type");
|
let this = this.downcast_mut().expect("invalid entity type");
|
||||||
on_release(this, cx);
|
on_release(this, cx);
|
||||||
|
@ -193,7 +202,7 @@ impl<'a, T: 'static> Context<'a, T> {
|
||||||
|
|
||||||
/// Tell GPUI that this entity has changed and observers of it should be notified.
|
/// Tell GPUI that this entity has changed and observers of it should be notified.
|
||||||
pub fn notify(&mut self) {
|
pub fn notify(&mut self) {
|
||||||
self.app.notify(self.entity_state.entity_id);
|
self.app.notify(self.entity_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Spawn the future returned by the given function.
|
/// Spawn the future returned by the given function.
|
||||||
|
@ -692,7 +701,7 @@ impl<T> Context<'_, T> {
|
||||||
Evt: 'static,
|
Evt: 'static,
|
||||||
{
|
{
|
||||||
self.app.pending_effects.push_back(Effect::Emit {
|
self.app.pending_effects.push_back(Effect::Emit {
|
||||||
emitter: self.entity_state.entity_id,
|
emitter: self.entity_id,
|
||||||
event_type: TypeId::of::<Evt>(),
|
event_type: TypeId::of::<Evt>(),
|
||||||
event: Box::new(event),
|
event: Box::new(event),
|
||||||
});
|
});
|
||||||
|
@ -706,16 +715,16 @@ impl<T> AppContext for Context<'_, T> {
|
||||||
self.app.new(build_entity)
|
self.app.new(build_entity)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reserve_entity<U: 'static>(&mut self) -> Reservation<U> {
|
fn reserve_entity(&mut self) -> EntityId {
|
||||||
self.app.reserve_entity()
|
self.app.reserve_entity()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_entity<U: 'static>(
|
fn insert_entity<U: 'static>(
|
||||||
&mut self,
|
&mut self,
|
||||||
reservation: Reservation<U>,
|
entity_id: EntityId,
|
||||||
build_entity: impl FnOnce(&mut Context<U>) -> U,
|
build_entity: impl FnOnce(&mut Context<U>) -> U,
|
||||||
) -> Self::Result<Entity<U>> {
|
) -> Self::Result<Entity<U>> {
|
||||||
self.app.insert_entity(reservation, build_entity)
|
self.app.insert_entity(entity_id, build_entity)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_entity<U: 'static, R>(
|
fn update_entity<U: 'static, R>(
|
||||||
|
|
|
@ -6,18 +6,18 @@ use parking_lot::{RwLock, RwLockUpgradableReadGuard};
|
||||||
use slotmap::{KeyData, SecondaryMap, SlotMap};
|
use slotmap::{KeyData, SecondaryMap, SlotMap};
|
||||||
use std::{
|
use std::{
|
||||||
any::{Any, TypeId, type_name},
|
any::{Any, TypeId, type_name},
|
||||||
cell::RefCell,
|
cell::{Ref, RefCell},
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
fmt::{self, Display},
|
fmt::{self, Display},
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
mem,
|
mem,
|
||||||
num::NonZeroU64,
|
num::NonZeroU64,
|
||||||
|
rc::{self, Rc},
|
||||||
sync::{
|
sync::{
|
||||||
Arc, Weak,
|
Arc, Weak,
|
||||||
atomic::{AtomicU64, AtomicUsize, Ordering::SeqCst},
|
atomic::{AtomicU64, AtomicUsize, Ordering::SeqCst},
|
||||||
},
|
},
|
||||||
thread::panicking,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::Context;
|
use super::Context;
|
||||||
|
@ -55,7 +55,7 @@ impl Display for EntityId {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct EntityMap {
|
pub(crate) struct EntityMap {
|
||||||
entities: SecondaryMap<EntityId, Box<dyn Any>>,
|
entities: SecondaryMap<EntityId, Rc<RefCell<dyn Any>>>,
|
||||||
pub accessed_entities: RefCell<FxHashSet<EntityId>>,
|
pub accessed_entities: RefCell<FxHashSet<EntityId>>,
|
||||||
ref_counts: Arc<RwLock<EntityRefCounts>>,
|
ref_counts: Arc<RwLock<EntityRefCounts>>,
|
||||||
}
|
}
|
||||||
|
@ -85,47 +85,28 @@ impl EntityMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reserve a slot for an entity, which you can subsequently use with `insert`.
|
/// Reserve a slot for an entity, which you can subsequently use with `insert`.
|
||||||
pub fn reserve<T: 'static>(&self) -> Slot<T> {
|
pub fn reserve(&self) -> EntityId {
|
||||||
let id = self.ref_counts.write().counts.insert(1.into());
|
self.ref_counts.write().counts.insert(AtomicUsize::new(1))
|
||||||
Slot(Entity::new(id, Arc::downgrade(&self.ref_counts)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Insert an entity into a slot obtained by calling `reserve`.
|
/// Insert an entity into a slot obtained by calling `reserve`.
|
||||||
pub fn insert<T>(&mut self, slot: Slot<T>, entity: T) -> Entity<T>
|
pub fn insert<T>(&mut self, entity_id: EntityId, entity: T) -> Entity<T>
|
||||||
where
|
where
|
||||||
T: 'static,
|
T: 'static,
|
||||||
{
|
{
|
||||||
let mut accessed_entities = self.accessed_entities.borrow_mut();
|
let mut accessed_entities = self.accessed_entities.borrow_mut();
|
||||||
accessed_entities.insert(slot.entity_id);
|
accessed_entities.insert(entity_id);
|
||||||
|
|
||||||
let handle = slot.0;
|
let entity_data = Rc::new(RefCell::new(entity));
|
||||||
self.entities.insert(handle.entity_id, Box::new(entity));
|
self.entities.insert(entity_id, entity_data.clone());
|
||||||
handle
|
|
||||||
|
Entity::new(entity_id, entity_data, Arc::downgrade(&self.ref_counts))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Move an entity to the stack.
|
pub fn get(&self, entity_id: EntityId) -> Rc<RefCell<dyn Any>> {
|
||||||
#[track_caller]
|
|
||||||
pub fn lease<'a, T>(&mut self, pointer: &'a Entity<T>) -> Lease<'a, T> {
|
|
||||||
self.assert_valid_context(pointer);
|
|
||||||
let mut accessed_entities = self.accessed_entities.borrow_mut();
|
let mut accessed_entities = self.accessed_entities.borrow_mut();
|
||||||
accessed_entities.insert(pointer.entity_id);
|
accessed_entities.insert(entity_id);
|
||||||
|
self.entities.get(entity_id).unwrap().clone()
|
||||||
let entity = Some(
|
|
||||||
self.entities
|
|
||||||
.remove(pointer.entity_id)
|
|
||||||
.unwrap_or_else(|| double_lease_panic::<T>("update")),
|
|
||||||
);
|
|
||||||
Lease {
|
|
||||||
entity,
|
|
||||||
pointer,
|
|
||||||
entity_type: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an entity after moving it to the stack.
|
|
||||||
pub fn end_lease<T>(&mut self, mut lease: Lease<T>) {
|
|
||||||
self.entities
|
|
||||||
.insert(lease.pointer.entity_id, lease.entity.take().unwrap());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read<T: 'static>(&self, entity: &Entity<T>) -> &T {
|
pub fn read<T: 'static>(&self, entity: &Entity<T>) -> &T {
|
||||||
|
@ -133,15 +114,16 @@ impl EntityMap {
|
||||||
let mut accessed_entities = self.accessed_entities.borrow_mut();
|
let mut accessed_entities = self.accessed_entities.borrow_mut();
|
||||||
accessed_entities.insert(entity.entity_id);
|
accessed_entities.insert(entity.entity_id);
|
||||||
|
|
||||||
self.entities
|
// self.entities
|
||||||
.get(entity.entity_id)
|
// .get(entity.entity_id)
|
||||||
.and_then(|entity| entity.downcast_ref())
|
// .and_then(|entity| entity.borrow().downcast_ref())
|
||||||
.unwrap_or_else(|| double_lease_panic::<T>("read"))
|
// .unwrap_or_else(|| double_lease_panic::<T>("read"))
|
||||||
|
todo!("interface will need to change here")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assert_valid_context(&self, entity: &AnyEntity) {
|
fn assert_valid_context(&self, entity: &AnyEntity) {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
Weak::ptr_eq(&entity.entity_map, &Arc::downgrade(&self.ref_counts)),
|
Weak::ptr_eq(&entity.ref_counts, &Arc::downgrade(&self.ref_counts)),
|
||||||
"used a entity with the wrong context"
|
"used a entity with the wrong context"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -156,7 +138,7 @@ impl EntityMap {
|
||||||
self.accessed_entities.borrow_mut().clear();
|
self.accessed_entities.borrow_mut().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn take_dropped(&mut self) -> Vec<(EntityId, Box<dyn Any>)> {
|
pub fn take_dropped(&mut self) -> Vec<(EntityId, Rc<RefCell<dyn Any>>)> {
|
||||||
let mut ref_counts = self.ref_counts.write();
|
let mut ref_counts = self.ref_counts.write();
|
||||||
let dropped_entity_ids = mem::take(&mut ref_counts.dropped_entity_ids);
|
let dropped_entity_ids = mem::take(&mut ref_counts.dropped_entity_ids);
|
||||||
let mut accessed_entities = self.accessed_entities.borrow_mut();
|
let mut accessed_entities = self.accessed_entities.borrow_mut();
|
||||||
|
@ -179,62 +161,30 @@ impl EntityMap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
|
||||||
fn double_lease_panic<T>(operation: &str) -> ! {
|
|
||||||
panic!(
|
|
||||||
"cannot {operation} {} while it is already being updated",
|
|
||||||
std::any::type_name::<T>()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct Lease<'a, T> {
|
|
||||||
entity: Option<Box<dyn Any>>,
|
|
||||||
pub pointer: &'a Entity<T>,
|
|
||||||
entity_type: PhantomData<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: 'static> core::ops::Deref for Lease<'_, T> {
|
|
||||||
type Target = T;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
self.entity.as_ref().unwrap().downcast_ref().unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: 'static> core::ops::DerefMut for Lease<'_, T> {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
self.entity.as_mut().unwrap().downcast_mut().unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Drop for Lease<'_, T> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
if self.entity.is_some() && !panicking() {
|
|
||||||
panic!("Leases must be ended with EntityMap::end_lease")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deref, DerefMut)]
|
|
||||||
pub(crate) struct Slot<T>(Entity<T>);
|
|
||||||
|
|
||||||
/// A dynamically typed reference to a entity, which can be downcast into a `Entity<T>`.
|
/// A dynamically typed reference to a entity, which can be downcast into a `Entity<T>`.
|
||||||
pub struct AnyEntity {
|
pub struct AnyEntity {
|
||||||
pub(crate) entity_id: EntityId,
|
pub(crate) entity_id: EntityId,
|
||||||
pub(crate) entity_type: TypeId,
|
pub(crate) entity_type: TypeId,
|
||||||
entity_map: Weak<RwLock<EntityRefCounts>>,
|
entity_data: Rc<RefCell<dyn Any>>,
|
||||||
|
ref_counts: Weak<RwLock<EntityRefCounts>>,
|
||||||
#[cfg(any(test, feature = "leak-detection"))]
|
#[cfg(any(test, feature = "leak-detection"))]
|
||||||
handle_id: HandleId,
|
handle_id: HandleId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AnyEntity {
|
impl AnyEntity {
|
||||||
fn new(id: EntityId, entity_type: TypeId, entity_map: Weak<RwLock<EntityRefCounts>>) -> Self {
|
fn new(
|
||||||
|
id: EntityId,
|
||||||
|
entity_type: TypeId,
|
||||||
|
entity_data: Rc<RefCell<dyn Any>>,
|
||||||
|
ref_counts: Weak<RwLock<EntityRefCounts>>,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
entity_id: id,
|
entity_id: id,
|
||||||
entity_type,
|
entity_type,
|
||||||
entity_map: entity_map.clone(),
|
entity_data,
|
||||||
|
ref_counts: ref_counts.clone(),
|
||||||
#[cfg(any(test, feature = "leak-detection"))]
|
#[cfg(any(test, feature = "leak-detection"))]
|
||||||
handle_id: entity_map
|
handle_id: ref_counts
|
||||||
.upgrade()
|
.upgrade()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.write()
|
.write()
|
||||||
|
@ -258,7 +208,8 @@ impl AnyEntity {
|
||||||
AnyWeakEntity {
|
AnyWeakEntity {
|
||||||
entity_id: self.entity_id,
|
entity_id: self.entity_id,
|
||||||
entity_type: self.entity_type,
|
entity_type: self.entity_type,
|
||||||
entity_ref_counts: self.entity_map.clone(),
|
entity_data: Rc::downgrade(&self.entity_data),
|
||||||
|
entity_ref_counts: self.ref_counts.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,7 +229,7 @@ impl AnyEntity {
|
||||||
|
|
||||||
impl Clone for AnyEntity {
|
impl Clone for AnyEntity {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
if let Some(entity_map) = self.entity_map.upgrade() {
|
if let Some(entity_map) = self.ref_counts.upgrade() {
|
||||||
let entity_map = entity_map.read();
|
let entity_map = entity_map.read();
|
||||||
let count = entity_map
|
let count = entity_map
|
||||||
.counts
|
.counts
|
||||||
|
@ -291,10 +242,11 @@ impl Clone for AnyEntity {
|
||||||
Self {
|
Self {
|
||||||
entity_id: self.entity_id,
|
entity_id: self.entity_id,
|
||||||
entity_type: self.entity_type,
|
entity_type: self.entity_type,
|
||||||
entity_map: self.entity_map.clone(),
|
entity_data: self.entity_data.clone(),
|
||||||
|
ref_counts: self.ref_counts.clone(),
|
||||||
#[cfg(any(test, feature = "leak-detection"))]
|
#[cfg(any(test, feature = "leak-detection"))]
|
||||||
handle_id: self
|
handle_id: self
|
||||||
.entity_map
|
.ref_counts
|
||||||
.upgrade()
|
.upgrade()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.write()
|
.write()
|
||||||
|
@ -306,7 +258,7 @@ impl Clone for AnyEntity {
|
||||||
|
|
||||||
impl Drop for AnyEntity {
|
impl Drop for AnyEntity {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if let Some(entity_map) = self.entity_map.upgrade() {
|
if let Some(entity_map) = self.ref_counts.upgrade() {
|
||||||
let entity_map = entity_map.upgradable_read();
|
let entity_map = entity_map.upgradable_read();
|
||||||
let count = entity_map
|
let count = entity_map
|
||||||
.counts
|
.counts
|
||||||
|
@ -322,7 +274,7 @@ impl Drop for AnyEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(test, feature = "leak-detection"))]
|
#[cfg(any(test, feature = "leak-detection"))]
|
||||||
if let Some(entity_map) = self.entity_map.upgrade() {
|
if let Some(entity_map) = self.ref_counts.upgrade() {
|
||||||
entity_map
|
entity_map
|
||||||
.write()
|
.write()
|
||||||
.leak_detector
|
.leak_detector
|
||||||
|
@ -386,12 +338,16 @@ unsafe impl<T> Sync for Entity<T> {}
|
||||||
impl<T> Sealed for Entity<T> {}
|
impl<T> Sealed for Entity<T> {}
|
||||||
|
|
||||||
impl<T: 'static> Entity<T> {
|
impl<T: 'static> Entity<T> {
|
||||||
fn new(id: EntityId, entity_map: Weak<RwLock<EntityRefCounts>>) -> Self
|
fn new(
|
||||||
|
id: EntityId,
|
||||||
|
entity_data: Rc<RefCell<T>>,
|
||||||
|
ref_counts: Weak<RwLock<EntityRefCounts>>,
|
||||||
|
) -> Self
|
||||||
where
|
where
|
||||||
T: 'static,
|
T: 'static,
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
any_entity: AnyEntity::new(id, TypeId::of::<T>(), entity_map),
|
any_entity: AnyEntity::new(id, TypeId::of::<T>(), entity_data, ref_counts),
|
||||||
entity_type: PhantomData,
|
entity_type: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -415,8 +371,11 @@ impl<T: 'static> Entity<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Grab a reference to this entity from the context.
|
/// Grab a reference to this entity from the context.
|
||||||
pub fn read<'a>(&self, cx: &'a App) -> &'a T {
|
/// todo! remove the cx param
|
||||||
cx.entities.read(self)
|
pub fn read(&self, _cx: &App) -> Ref<T> {
|
||||||
|
Ref::map(self.any_entity.entity_data.borrow(), |data| {
|
||||||
|
data.downcast_ref().unwrap()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read the entity referenced by this handle with the given function.
|
/// Read the entity referenced by this handle with the given function.
|
||||||
|
@ -504,6 +463,7 @@ impl<T: 'static> PartialOrd for Entity<T> {
|
||||||
pub struct AnyWeakEntity {
|
pub struct AnyWeakEntity {
|
||||||
pub(crate) entity_id: EntityId,
|
pub(crate) entity_id: EntityId,
|
||||||
entity_type: TypeId,
|
entity_type: TypeId,
|
||||||
|
entity_data: rc::Weak<RefCell<dyn Any>>,
|
||||||
entity_ref_counts: Weak<RwLock<EntityRefCounts>>,
|
entity_ref_counts: Weak<RwLock<EntityRefCounts>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -538,7 +498,8 @@ impl AnyWeakEntity {
|
||||||
Some(AnyEntity {
|
Some(AnyEntity {
|
||||||
entity_id: self.entity_id,
|
entity_id: self.entity_id,
|
||||||
entity_type: self.entity_type,
|
entity_type: self.entity_type,
|
||||||
entity_map: self.entity_ref_counts.clone(),
|
entity_data: self.entity_data.upgrade()?,
|
||||||
|
ref_counts: self.entity_ref_counts.clone(),
|
||||||
#[cfg(any(test, feature = "leak-detection"))]
|
#[cfg(any(test, feature = "leak-detection"))]
|
||||||
handle_id: self
|
handle_id: self
|
||||||
.entity_ref_counts
|
.entity_ref_counts
|
||||||
|
@ -592,6 +553,7 @@ impl AnyWeakEntity {
|
||||||
// read in the first place, so we're good!
|
// read in the first place, so we're good!
|
||||||
entity_id: entity_id.into(),
|
entity_id: entity_id.into(),
|
||||||
entity_type: TypeId::of::<()>(),
|
entity_type: TypeId::of::<()>(),
|
||||||
|
entity_data: Rc::downgrade(&(Rc::new(RefCell::new(())) as Rc<RefCell<dyn Any>>)),
|
||||||
entity_ref_counts: Weak::new(),
|
entity_ref_counts: Weak::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -836,10 +798,10 @@ mod test {
|
||||||
// Tests that slots are not re-used before take_dropped.
|
// Tests that slots are not re-used before take_dropped.
|
||||||
let mut entity_map = EntityMap::new();
|
let mut entity_map = EntityMap::new();
|
||||||
|
|
||||||
let slot = entity_map.reserve::<TestEntity>();
|
let slot = entity_map.reserve();
|
||||||
entity_map.insert(slot, TestEntity { i: 1 });
|
entity_map.insert(slot, TestEntity { i: 1 });
|
||||||
|
|
||||||
let slot = entity_map.reserve::<TestEntity>();
|
let slot = entity_map.reserve();
|
||||||
entity_map.insert(slot, TestEntity { i: 2 });
|
entity_map.insert(slot, TestEntity { i: 2 });
|
||||||
|
|
||||||
let dropped = entity_map.take_dropped();
|
let dropped = entity_map.take_dropped();
|
||||||
|
@ -848,7 +810,7 @@ mod test {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
dropped
|
dropped
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(_, entity)| entity.downcast::<TestEntity>().unwrap().i)
|
.map(|(_, entity)| entity.borrow().downcast_ref::<TestEntity>().unwrap().i)
|
||||||
.collect::<Vec<i32>>(),
|
.collect::<Vec<i32>>(),
|
||||||
vec![1, 2],
|
vec![1, 2],
|
||||||
);
|
);
|
||||||
|
@ -859,7 +821,7 @@ mod test {
|
||||||
// Tests that weak handles are not upgraded before take_dropped
|
// Tests that weak handles are not upgraded before take_dropped
|
||||||
let mut entity_map = EntityMap::new();
|
let mut entity_map = EntityMap::new();
|
||||||
|
|
||||||
let slot = entity_map.reserve::<TestEntity>();
|
let slot = entity_map.reserve();
|
||||||
let handle = entity_map.insert(slot, TestEntity { i: 1 });
|
let handle = entity_map.insert(slot, TestEntity { i: 1 });
|
||||||
let weak = handle.downgrade();
|
let weak = handle.downgrade();
|
||||||
drop(handle);
|
drop(handle);
|
||||||
|
@ -873,7 +835,7 @@ mod test {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
dropped
|
dropped
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(_, entity)| entity.downcast::<TestEntity>().unwrap().i)
|
.map(|(_, entity)| entity.borrow().downcast_ref::<TestEntity>().unwrap().i)
|
||||||
.collect::<Vec<i32>>(),
|
.collect::<Vec<i32>>(),
|
||||||
vec![1],
|
vec![1],
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
Action, AnyView, AnyWindowHandle, App, AppCell, AppContext, AsyncApp, AvailableSpace,
|
Action, AnyView, AnyWindowHandle, App, AppCell, AppContext, AsyncApp, AvailableSpace,
|
||||||
BackgroundExecutor, BorrowAppContext, Bounds, Capslock, ClipboardItem, DrawPhase, Drawable,
|
BackgroundExecutor, BorrowAppContext, Bounds, Capslock, ClipboardItem, DrawPhase, Drawable,
|
||||||
Element, Empty, EventEmitter, ForegroundExecutor, Global, InputEvent, Keystroke, Modifiers,
|
Element, Empty, EntityId, EventEmitter, ForegroundExecutor, Global, InputEvent, Keystroke,
|
||||||
ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels,
|
Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent,
|
||||||
Platform, Point, Render, Result, Size, Task, TestDispatcher, TestPlatform,
|
Pixels, Platform, Point, Render, Result, Size, Task, TestDispatcher, TestPlatform,
|
||||||
TestScreenCaptureSource, TestWindow, TextSystem, VisualContext, Window, WindowBounds,
|
TestScreenCaptureSource, TestWindow, TextSystem, VisualContext, Window, WindowBounds,
|
||||||
WindowHandle, WindowOptions,
|
WindowHandle, WindowOptions,
|
||||||
};
|
};
|
||||||
|
@ -40,14 +40,14 @@ impl AppContext for TestAppContext {
|
||||||
app.new(build_entity)
|
app.new(build_entity)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reserve_entity<T: 'static>(&mut self) -> Self::Result<crate::Reservation<T>> {
|
fn reserve_entity(&mut self) -> Self::Result<EntityId> {
|
||||||
let mut app = self.app.borrow_mut();
|
let mut app = self.app.borrow_mut();
|
||||||
app.reserve_entity()
|
app.reserve_entity()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_entity<T: 'static>(
|
fn insert_entity<T: 'static>(
|
||||||
&mut self,
|
&mut self,
|
||||||
reservation: crate::Reservation<T>,
|
reservation: EntityId,
|
||||||
build_entity: impl FnOnce(&mut Context<T>) -> T,
|
build_entity: impl FnOnce(&mut Context<T>) -> T,
|
||||||
) -> Self::Result<Entity<T>> {
|
) -> Self::Result<Entity<T>> {
|
||||||
let mut app = self.app.borrow_mut();
|
let mut app = self.app.borrow_mut();
|
||||||
|
@ -624,7 +624,8 @@ impl<V> Entity<V> {
|
||||||
handle
|
handle
|
||||||
.upgrade()
|
.upgrade()
|
||||||
.expect("view dropped with pending condition")
|
.expect("view dropped with pending condition")
|
||||||
.read(cx),
|
.read(cx)
|
||||||
|
.deref(),
|
||||||
cx,
|
cx,
|
||||||
) {
|
) {
|
||||||
break;
|
break;
|
||||||
|
@ -891,13 +892,13 @@ impl AppContext for VisualTestContext {
|
||||||
self.cx.new(build_entity)
|
self.cx.new(build_entity)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reserve_entity<T: 'static>(&mut self) -> Self::Result<crate::Reservation<T>> {
|
fn reserve_entity(&mut self) -> Self::Result<EntityId> {
|
||||||
self.cx.reserve_entity()
|
self.cx.reserve_entity()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_entity<T: 'static>(
|
fn insert_entity<T: 'static>(
|
||||||
&mut self,
|
&mut self,
|
||||||
reservation: crate::Reservation<T>,
|
reservation: EntityId,
|
||||||
build_entity: impl FnOnce(&mut Context<T>) -> T,
|
build_entity: impl FnOnce(&mut Context<T>) -> T,
|
||||||
) -> Self::Result<Entity<T>> {
|
) -> Self::Result<Entity<T>> {
|
||||||
self.cx.insert_entity(reservation, build_entity)
|
self.cx.insert_entity(reservation, build_entity)
|
||||||
|
|
|
@ -175,16 +175,15 @@ pub trait AppContext {
|
||||||
build_entity: impl FnOnce(&mut Context<T>) -> T,
|
build_entity: impl FnOnce(&mut Context<T>) -> T,
|
||||||
) -> Self::Result<Entity<T>>;
|
) -> Self::Result<Entity<T>>;
|
||||||
|
|
||||||
/// Reserve a slot for a entity to be inserted later.
|
/// Reserve an EntityId for a entity to be inserted later.
|
||||||
/// The returned [Reservation] allows you to obtain the [EntityId] for the future entity.
|
fn reserve_entity(&mut self) -> Self::Result<EntityId>;
|
||||||
fn reserve_entity<T: 'static>(&mut self) -> Self::Result<Reservation<T>>;
|
|
||||||
|
|
||||||
/// Insert a new entity in the app context based on a [Reservation] previously obtained from [`reserve_entity`].
|
/// Insert a new entity in the app context based on a [EntityId] previously obtained from [`reserve_entity`].
|
||||||
///
|
///
|
||||||
/// [`reserve_entity`]: Self::reserve_entity
|
/// [`reserve_entity`]: Self::reserve_entity
|
||||||
fn insert_entity<T: 'static>(
|
fn insert_entity<T: 'static>(
|
||||||
&mut self,
|
&mut self,
|
||||||
reservation: Reservation<T>,
|
reservation: EntityId,
|
||||||
build_entity: impl FnOnce(&mut Context<T>) -> T,
|
build_entity: impl FnOnce(&mut Context<T>) -> T,
|
||||||
) -> Self::Result<Entity<T>>;
|
) -> Self::Result<Entity<T>>;
|
||||||
|
|
||||||
|
@ -231,17 +230,6 @@ pub trait AppContext {
|
||||||
G: Global;
|
G: Global;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returned by [Context::reserve_entity] to later be passed to [Context::insert_entity].
|
|
||||||
/// Allows you to obtain the [EntityId] for a entity before it is created.
|
|
||||||
pub struct Reservation<T>(pub(crate) Slot<T>);
|
|
||||||
|
|
||||||
impl<T: 'static> Reservation<T> {
|
|
||||||
/// Returns the [EntityId] that will be associated with the entity once it is inserted.
|
|
||||||
pub fn entity_id(&self) -> EntityId {
|
|
||||||
self.0.entity_id()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This trait is used for the different visual contexts in GPUI that
|
/// This trait is used for the different visual contexts in GPUI that
|
||||||
/// require a window to be present.
|
/// require a window to be present.
|
||||||
pub trait VisualContext: AppContext {
|
pub trait VisualContext: AppContext {
|
||||||
|
|
|
@ -31,6 +31,8 @@ use raw_window_handle::{HandleError, HasDisplayHandle, HasWindowHandle};
|
||||||
use refineable::Refineable;
|
use refineable::Refineable;
|
||||||
use slotmap::SlotMap;
|
use slotmap::SlotMap;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
use std::cell::Ref;
|
||||||
|
use std::ops::Deref;
|
||||||
use std::{
|
use std::{
|
||||||
any::{Any, TypeId},
|
any::{Any, TypeId},
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
|
@ -4139,7 +4141,8 @@ impl Window {
|
||||||
if let Some(inspector_id) = _inspector_id {
|
if let Some(inspector_id) = _inspector_id {
|
||||||
if let Some(inspector) = &self.inspector {
|
if let Some(inspector) = &self.inspector {
|
||||||
let inspector = inspector.clone();
|
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 {
|
if Some(inspector_id) == active_element_id {
|
||||||
return inspector.update(cx, |inspector, _cx| {
|
return inspector.update(cx, |inspector, _cx| {
|
||||||
inspector.with_active_element_state(self, f)
|
inspector.with_active_element_state(self, f)
|
||||||
|
@ -4213,9 +4216,9 @@ impl Window {
|
||||||
|
|
||||||
#[cfg(any(feature = "inspector", debug_assertions))]
|
#[cfg(any(feature = "inspector", debug_assertions))]
|
||||||
fn paint_inspector_hitbox(&mut self, cx: &App) {
|
fn paint_inspector_hitbox(&mut self, cx: &App) {
|
||||||
if let Some(inspector) = self.inspector.as_ref() {
|
if let Some(inspector) = self.inspector.clone() {
|
||||||
let inspector = inspector.read(cx);
|
if let Some((hitbox_id, _)) =
|
||||||
if let Some((hitbox_id, _)) = self.hovered_inspector_hitbox(inspector, &self.next_frame)
|
self.hovered_inspector_hitbox(inspector.read(cx).deref(), &self.next_frame)
|
||||||
{
|
{
|
||||||
if let Some(hitbox) = self
|
if let Some(hitbox) = self
|
||||||
.next_frame
|
.next_frame
|
||||||
|
@ -4379,7 +4382,7 @@ impl<V: 'static + Render> WindowHandle<V> {
|
||||||
/// Read the root view out of this window.
|
/// 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`.
|
/// 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<Ref<V>> {
|
||||||
let x = cx
|
let x = cx
|
||||||
.windows
|
.windows
|
||||||
.get(self.id)
|
.get(self.id)
|
||||||
|
@ -4392,7 +4395,7 @@ impl<V: 'static + Render> WindowHandle<V> {
|
||||||
.context("window not found")?
|
.context("window not found")?
|
||||||
.map_err(|_| anyhow!("the type of the window's root view has changed"))?;
|
.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
|
/// Read the root view out of this window, with a callback
|
||||||
|
@ -4402,7 +4405,9 @@ impl<V: 'static + Render> WindowHandle<V> {
|
||||||
where
|
where
|
||||||
C: AppContext,
|
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.
|
/// Read the root view pointer off of this window.
|
||||||
|
|
|
@ -30,16 +30,16 @@ pub fn derive_app_context(input: TokenStream) -> TokenStream {
|
||||||
self.#app_variable.new(build_entity)
|
self.#app_variable.new(build_entity)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reserve_entity<T: 'static>(&mut self) -> Self::Result<gpui::Reservation<T>> {
|
fn reserve_entity(&mut self) -> Self::Result<EntityId> {
|
||||||
self.#app_variable.reserve_entity()
|
self.#app_variable.reserve_entity()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_entity<T: 'static>(
|
fn insert_entity<T: 'static>(
|
||||||
&mut self,
|
&mut self,
|
||||||
reservation: gpui::Reservation<T>,
|
entity_id: EntityId,
|
||||||
build_entity: impl FnOnce(&mut gpui::Context<'_, T>) -> T,
|
build_entity: impl FnOnce(&mut gpui::Context<'_, T>) -> T,
|
||||||
) -> Self::Result<gpui::Entity<T>> {
|
) -> Self::Result<gpui::Entity<T>> {
|
||||||
self.#app_variable.insert_entity(reservation, build_entity)
|
self.#app_variable.insert_entity(entity_id, build_entity)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_entity<T, R>(
|
fn update_entity<T, R>(
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#[test]
|
#[test]
|
||||||
fn test_derive_context() {
|
fn test_derive_context() {
|
||||||
use gpui::{App, Window};
|
use gpui::{App, EntityId, Window};
|
||||||
use gpui_macros::{AppContext, VisualContext};
|
use gpui_macros::{AppContext, VisualContext};
|
||||||
|
|
||||||
#[derive(AppContext, VisualContext)]
|
#[derive(AppContext, VisualContext)]
|
||||||
|
|
|
@ -41,7 +41,7 @@ use std::{
|
||||||
cell::Cell,
|
cell::Cell,
|
||||||
cmp::{self, Ordering, Reverse},
|
cmp::{self, Ordering, Reverse},
|
||||||
collections::{BTreeMap, BTreeSet},
|
collections::{BTreeMap, BTreeSet},
|
||||||
ffi::OsStr,
|
ffi::{OsStr, OsString},
|
||||||
future::Future,
|
future::Future,
|
||||||
iter::{self, Iterator, Peekable},
|
iter::{self, Iterator, Peekable},
|
||||||
mem,
|
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
|
/// 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.
|
/// 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.
|
/// Returns the id of the worktree to which this file belongs.
|
||||||
///
|
///
|
||||||
|
@ -967,7 +967,7 @@ impl Buffer {
|
||||||
language_registry: Option<Arc<LanguageRegistry>>,
|
language_registry: Option<Arc<LanguageRegistry>>,
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) -> impl Future<Output = BufferSnapshot> + use<> {
|
) -> impl Future<Output = BufferSnapshot> + use<> {
|
||||||
let entity_id = cx.reserve_entity::<Self>().entity_id();
|
let entity_id = cx.reserve_entity();
|
||||||
let buffer_id = entity_id.as_non_zero_u64().into();
|
let buffer_id = entity_id.as_non_zero_u64().into();
|
||||||
async move {
|
async move {
|
||||||
let text =
|
let text =
|
||||||
|
@ -992,7 +992,7 @@ impl Buffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_empty_snapshot(cx: &mut App) -> BufferSnapshot {
|
pub fn build_empty_snapshot(cx: &mut App) -> BufferSnapshot {
|
||||||
let entity_id = cx.reserve_entity::<Self>().entity_id();
|
let entity_id = cx.reserve_entity();
|
||||||
let buffer_id = entity_id.as_non_zero_u64().into();
|
let buffer_id = entity_id.as_non_zero_u64().into();
|
||||||
let text =
|
let text =
|
||||||
TextBuffer::new_normalized(0, buffer_id, Default::default(), Rope::new()).snapshot();
|
TextBuffer::new_normalized(0, buffer_id, Default::default(), Rope::new()).snapshot();
|
||||||
|
@ -1015,7 +1015,7 @@ impl Buffer {
|
||||||
language_registry: Option<Arc<LanguageRegistry>>,
|
language_registry: Option<Arc<LanguageRegistry>>,
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) -> BufferSnapshot {
|
) -> BufferSnapshot {
|
||||||
let entity_id = cx.reserve_entity::<Self>().entity_id();
|
let entity_id = cx.reserve_entity();
|
||||||
let buffer_id = entity_id.as_non_zero_u64().into();
|
let buffer_id = entity_id.as_non_zero_u64().into();
|
||||||
let text = TextBuffer::new_normalized(0, buffer_id, Default::default(), text).snapshot();
|
let text = TextBuffer::new_normalized(0, buffer_id, Default::default(), text).snapshot();
|
||||||
let mut syntax = SyntaxMap::new(&text).snapshot();
|
let mut syntax = SyntaxMap::new(&text).snapshot();
|
||||||
|
@ -4895,8 +4895,11 @@ impl File for TestFile {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file_name<'a>(&'a self, _: &'a gpui::App) -> &'a std::ffi::OsStr {
|
fn file_name<'a>(&'a self, _: &'a gpui::App) -> OsString {
|
||||||
self.path().file_name().unwrap_or(self.root_name.as_ref())
|
self.path()
|
||||||
|
.file_name()
|
||||||
|
.unwrap_or(self.root_name.as_ref())
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn worktree_id(&self, _: &App) -> WorktreeId {
|
fn worktree_id(&self, _: &App) -> WorktreeId {
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use collections::BTreeMap;
|
use collections::BTreeMap;
|
||||||
use gpui::{App, Context, Entity, EventEmitter, Global, prelude::*};
|
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 thiserror::Error;
|
||||||
use util::maybe;
|
use util::maybe;
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ impl LanguageModelRegistry {
|
||||||
cx.global::<GlobalLanguageModelRegistry>().0.clone()
|
cx.global::<GlobalLanguageModelRegistry>().0.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_global(cx: &App) -> &Self {
|
pub fn read_global(cx: &App) -> Ref<Self> {
|
||||||
cx.global::<GlobalLanguageModelRegistry>().0.read(cx)
|
cx.global::<GlobalLanguageModelRegistry>().0.read(cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1215,8 +1215,9 @@ impl MultiBuffer {
|
||||||
if let Some(excerpt) = cursor.item() {
|
if let Some(excerpt) = cursor.item() {
|
||||||
if excerpt.locator == *excerpt_id {
|
if excerpt.locator == *excerpt_id {
|
||||||
let excerpt_buffer_start =
|
let excerpt_buffer_start =
|
||||||
excerpt.range.context.start.summary::<D>(buffer);
|
excerpt.range.context.start.summary::<D>(&buffer);
|
||||||
let excerpt_buffer_end = excerpt.range.context.end.summary::<D>(buffer);
|
let excerpt_buffer_end =
|
||||||
|
excerpt.range.context.end.summary::<D>(&buffer);
|
||||||
let excerpt_range = excerpt_buffer_start..excerpt_buffer_end;
|
let excerpt_range = excerpt_buffer_start..excerpt_buffer_end;
|
||||||
if excerpt_range.contains(&range.start)
|
if excerpt_range.contains(&range.start)
|
||||||
&& excerpt_range.contains(&range.end)
|
&& excerpt_range.contains(&range.end)
|
||||||
|
@ -2477,7 +2478,7 @@ impl MultiBuffer {
|
||||||
};
|
};
|
||||||
|
|
||||||
let buffer = buffer_state.buffer.read(cx);
|
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 new_diff = diff.snapshot(cx);
|
||||||
let mut snapshot = self.snapshot.borrow_mut();
|
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> {
|
pub fn language_settings<'a>(&'a self, cx: &'a App) -> Cow<'a, LanguageSettings> {
|
||||||
let buffer_id = self
|
// let buffer_id = self
|
||||||
.snapshot
|
// .snapshot
|
||||||
.borrow()
|
// .borrow()
|
||||||
.excerpts
|
// .excerpts
|
||||||
.first()
|
// .first()
|
||||||
.map(|excerpt| excerpt.buffer.remote_id());
|
// .map(|excerpt| excerpt.buffer.remote_id());
|
||||||
buffer_id
|
// buffer_id
|
||||||
.and_then(|buffer_id| self.buffer(buffer_id))
|
// .and_then(|buffer_id| self.buffer(buffer_id))
|
||||||
.map(|buffer| {
|
// .map(|buffer| {
|
||||||
let buffer = buffer.read(cx);
|
// let buffer = buffer.read(cx);
|
||||||
language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
|
// language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
|
||||||
})
|
// })
|
||||||
.unwrap_or_else(move || self.language_settings_at(0, cx))
|
// .unwrap_or_else(move || self.language_settings_at(0, cx))
|
||||||
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn language_settings_at<'a, T: ToOffset>(
|
pub fn language_settings_at<'a, T: ToOffset>(
|
||||||
|
@ -2585,7 +2587,8 @@ impl MultiBuffer {
|
||||||
language = buffer.language_at(offset);
|
language = buffer.language_at(offset);
|
||||||
file = buffer.file();
|
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<Buffer>)) {
|
pub fn for_each_buffer(&self, mut f: impl FnMut(&Entity<Buffer>)) {
|
||||||
|
@ -2596,23 +2599,24 @@ impl MultiBuffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn title<'a>(&'a self, cx: &'a App) -> Cow<'a, str> {
|
pub fn title<'a>(&'a self, cx: &'a App) -> Cow<'a, str> {
|
||||||
if let Some(title) = self.title.as_ref() {
|
// if let Some(title) = self.title.as_ref() {
|
||||||
return title.into();
|
// return title.into();
|
||||||
}
|
// }
|
||||||
|
|
||||||
if let Some(buffer) = self.as_singleton() {
|
// if let Some(buffer) = self.as_singleton() {
|
||||||
let buffer = buffer.read(cx);
|
// let buffer = buffer.read(cx);
|
||||||
|
|
||||||
if let Some(file) = buffer.file() {
|
// if let Some(file) = buffer.file() {
|
||||||
return file.file_name(cx).to_string_lossy();
|
// return file.file_name(cx).to_string_lossy();
|
||||||
}
|
// }
|
||||||
|
|
||||||
if let Some(title) = self.buffer_content_title(buffer) {
|
// if let Some(title) = self.buffer_content_title(&buffer) {
|
||||||
return title;
|
// return title;
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
|
|
||||||
"untitled".into()
|
// "untitled".into()
|
||||||
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn buffer_content_title(&self, buffer: &Buffer) -> Option<Cow<'_, str>> {
|
fn buffer_content_title(&self, buffer: &Buffer) -> Option<Cow<'_, str>> {
|
||||||
|
|
|
@ -126,6 +126,7 @@ impl RemoteBufferStore {
|
||||||
let version = buffer.version();
|
let version = buffer.version();
|
||||||
let rpc = self.upstream_client.clone();
|
let rpc = self.upstream_client.clone();
|
||||||
let project_id = self.project_id;
|
let project_id = self.project_id;
|
||||||
|
drop(buffer);
|
||||||
cx.spawn(async move |_, cx| {
|
cx.spawn(async move |_, cx| {
|
||||||
let response = rpc
|
let response = rpc
|
||||||
.request(proto::SaveBuffer {
|
.request(proto::SaveBuffer {
|
||||||
|
@ -373,6 +374,7 @@ impl LocalBufferStore {
|
||||||
let save = worktree.update(cx, |worktree, cx| {
|
let save = worktree.update(cx, |worktree, cx| {
|
||||||
worktree.write_file(path.as_ref(), text, line_ending, cx)
|
worktree.write_file(path.as_ref(), text, line_ending, cx)
|
||||||
});
|
});
|
||||||
|
drop(buffer);
|
||||||
|
|
||||||
cx.spawn(async move |this, cx| {
|
cx.spawn(async move |this, cx| {
|
||||||
let new_file = save.await?;
|
let new_file = save.await?;
|
||||||
|
@ -574,11 +576,14 @@ impl LocalBufferStore {
|
||||||
buffer: Entity<Buffer>,
|
buffer: Entity<Buffer>,
|
||||||
cx: &mut Context<BufferStore>,
|
cx: &mut Context<BufferStore>,
|
||||||
) -> Task<Result<()>> {
|
) -> Task<Result<()>> {
|
||||||
let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
|
let (worktree, path) = {
|
||||||
|
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")));
|
return Task::ready(Err(anyhow!("buffer doesn't have a file")));
|
||||||
};
|
};
|
||||||
let worktree = file.worktree.clone();
|
(file.worktree.clone(), file.path.clone())
|
||||||
self.save_local_buffer(buffer, worktree, file.path.clone(), false, cx)
|
};
|
||||||
|
self.save_local_buffer(buffer, worktree, path, false, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save_buffer_as(
|
fn save_buffer_as(
|
||||||
|
@ -605,14 +610,14 @@ impl LocalBufferStore {
|
||||||
) -> Task<Result<Entity<Buffer>>> {
|
) -> Task<Result<Entity<Buffer>>> {
|
||||||
let load_buffer = worktree.update(cx, |worktree, cx| {
|
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(), cx);
|
||||||
let reservation = cx.reserve_entity();
|
let entity_id = cx.reserve_entity();
|
||||||
let buffer_id = BufferId::from(reservation.entity_id().as_non_zero_u64());
|
let buffer_id = BufferId::from(entity_id.as_non_zero_u64());
|
||||||
cx.spawn(async move |_, cx| {
|
cx.spawn(async move |_, cx| {
|
||||||
let loaded = load_file.await?;
|
let loaded = load_file.await?;
|
||||||
let text_buffer = cx
|
let text_buffer = cx
|
||||||
.background_spawn(async move { text::Buffer::new(0, buffer_id, loaded.text) })
|
.background_spawn(async move { text::Buffer::new(0, buffer_id, loaded.text) })
|
||||||
.await;
|
.await;
|
||||||
cx.insert_entity(reservation, |_| {
|
cx.insert_entity(entity_id, |_| {
|
||||||
Buffer::build(text_buffer, Some(loaded.file), Capability::ReadWrite)
|
Buffer::build(text_buffer, Some(loaded.file), Capability::ReadWrite)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -922,6 +927,7 @@ impl BufferStore {
|
||||||
self.path_to_buffer_id.insert(path, remote_id);
|
self.path_to_buffer_id.insert(path, remote_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
drop(buffer);
|
||||||
cx.subscribe(&buffer_entity, Self::on_buffer_event).detach();
|
cx.subscribe(&buffer_entity, Self::on_buffer_event).detach();
|
||||||
cx.emit(BufferStoreEvent::BufferAdded(buffer_entity));
|
cx.emit(BufferStoreEvent::BufferAdded(buffer_entity));
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1022,9 +1028,9 @@ impl BufferStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn buffer_changed_file(&mut self, buffer: Entity<Buffer>, cx: &mut App) -> Option<()> {
|
fn buffer_changed_file(&mut self, buffer: Entity<Buffer>, cx: &mut App) -> Option<()> {
|
||||||
let file = File::from_dyn(buffer.read(cx).file())?;
|
let buffer_ref = buffer.read(cx);
|
||||||
|
let file = File::from_dyn(buffer_ref.file())?;
|
||||||
let remote_id = buffer.read(cx).remote_id();
|
let remote_id = buffer_ref.remote_id();
|
||||||
if let Some(entry_id) = file.entry_id {
|
if let Some(entry_id) = file.entry_id {
|
||||||
if let Some(local) = self.as_local_mut() {
|
if let Some(local) = self.as_local_mut() {
|
||||||
match local.local_buffer_ids_by_entry_id.get(&entry_id) {
|
match local.local_buffer_ids_by_entry_id.get(&entry_id) {
|
||||||
|
@ -1061,10 +1067,13 @@ impl BufferStore {
|
||||||
let mut open_buffers = HashSet::default();
|
let mut open_buffers = HashSet::default();
|
||||||
let mut unnamed_buffers = Vec::new();
|
let mut unnamed_buffers = Vec::new();
|
||||||
for handle in self.buffers() {
|
for handle in self.buffers() {
|
||||||
|
let (remote_id, entry_id) = {
|
||||||
let buffer = handle.read(cx);
|
let buffer = handle.read(cx);
|
||||||
if self.non_searchable_buffers.contains(&buffer.remote_id()) {
|
(buffer.remote_id(), buffer.entry_id(cx))
|
||||||
|
};
|
||||||
|
if self.non_searchable_buffers.contains(&remote_id) {
|
||||||
continue;
|
continue;
|
||||||
} else if let Some(entry_id) = buffer.entry_id(cx) {
|
} else if let Some(entry_id) = entry_id {
|
||||||
open_buffers.insert(entry_id);
|
open_buffers.insert(entry_id);
|
||||||
} else {
|
} else {
|
||||||
limit = limit.saturating_sub(1);
|
limit = limit.saturating_sub(1);
|
||||||
|
|
|
@ -155,7 +155,7 @@ impl DapStore {
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mode = DapStoreMode::Ssh(SshDapStore {
|
let mode = DapStoreMode::Ssh(SshDapStore {
|
||||||
upstream_client: ssh_client.read(cx).proto_client(),
|
upstream_client: ssh_client.read(cx).proto_client(),
|
||||||
ssh_client,
|
ssh_client: ssh_client.clone(),
|
||||||
upstream_project_id: project_id,
|
upstream_project_id: project_id,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -947,14 +947,18 @@ impl GitStore {
|
||||||
selection: Range<u32>,
|
selection: Range<u32>,
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) -> Task<Result<url::Url>> {
|
) -> Task<Result<url::Url>> {
|
||||||
let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
|
let (worktree, path) = {
|
||||||
|
let buffer_ref = buffer.read(cx);
|
||||||
|
let Some(file) = File::from_dyn(buffer_ref.file()) else {
|
||||||
return Task::ready(Err(anyhow!("buffer has no file")));
|
return Task::ready(Err(anyhow!("buffer has no file")));
|
||||||
};
|
};
|
||||||
|
(file.worktree.clone(), file.path.clone())
|
||||||
|
};
|
||||||
|
|
||||||
let Some((repo, repo_path)) = self.repository_and_path_for_project_path(
|
let worktree_id = worktree.read(cx).id();
|
||||||
&(file.worktree.read(cx).id(), file.path.clone()).into(),
|
let Some((repo, repo_path)) =
|
||||||
cx,
|
self.repository_and_path_for_project_path(&(worktree_id, path.clone()).into(), cx)
|
||||||
) else {
|
else {
|
||||||
// If we're not in a Git repo, check whether this is a Rust source
|
// If we're not in a Git repo, check whether this is a Rust source
|
||||||
// file in the Cargo registry (presumably opened with go-to-definition
|
// file in the Cargo registry (presumably opened with go-to-definition
|
||||||
// from a normal Rust file). If so, we can put together a permalink
|
// from a normal Rust file). If so, we can put together a permalink
|
||||||
|
@ -966,7 +970,7 @@ impl GitStore {
|
||||||
{
|
{
|
||||||
return Task::ready(Err(anyhow!("no permalink available")));
|
return Task::ready(Err(anyhow!("no permalink available")));
|
||||||
}
|
}
|
||||||
let Some(file_path) = file.worktree.read(cx).absolutize(&file.path).ok() else {
|
let Some(file_path) = worktree.read(cx).absolutize(&path).ok() else {
|
||||||
return Task::ready(Err(anyhow!("no permalink available")));
|
return Task::ready(Err(anyhow!("no permalink available")));
|
||||||
};
|
};
|
||||||
return cx.spawn(async move |cx| {
|
return cx.spawn(async move |cx| {
|
||||||
|
@ -2062,7 +2066,7 @@ impl GitStore {
|
||||||
.or_default();
|
.or_default();
|
||||||
shared_diffs.entry(buffer_id).or_default().uncommitted = Some(diff.clone());
|
shared_diffs.entry(buffer_id).or_default().uncommitted = Some(diff.clone());
|
||||||
})?;
|
})?;
|
||||||
diff.read_with(&cx, |diff, cx| {
|
Ok(diff.read_with(&cx, |diff, cx| {
|
||||||
use proto::open_uncommitted_diff_response::Mode;
|
use proto::open_uncommitted_diff_response::Mode;
|
||||||
|
|
||||||
let unstaged_diff = diff.secondary_diff();
|
let unstaged_diff = diff.secondary_diff();
|
||||||
|
@ -2076,14 +2080,14 @@ impl GitStore {
|
||||||
let committed_text;
|
let committed_text;
|
||||||
if diff.base_text_exists() {
|
if diff.base_text_exists() {
|
||||||
let committed_snapshot = diff.base_text();
|
let committed_snapshot = diff.base_text();
|
||||||
committed_text = Some(committed_snapshot.text());
|
committed_text = Some(committed_snapshot.text().to_string());
|
||||||
if let Some(index_text) = index_snapshot {
|
if let Some(index_text) = index_snapshot {
|
||||||
if index_text.remote_id() == committed_snapshot.remote_id() {
|
if index_text.remote_id() == committed_snapshot.remote_id() {
|
||||||
mode = Mode::IndexMatchesHead;
|
mode = Mode::IndexMatchesHead;
|
||||||
staged_text = None;
|
staged_text = None;
|
||||||
} else {
|
} else {
|
||||||
mode = Mode::IndexAndHead;
|
mode = Mode::IndexAndHead;
|
||||||
staged_text = Some(index_text.text());
|
staged_text = Some(index_text.text().to_string());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mode = Mode::IndexAndHead;
|
mode = Mode::IndexAndHead;
|
||||||
|
@ -2092,15 +2096,17 @@ impl GitStore {
|
||||||
} else {
|
} else {
|
||||||
mode = Mode::IndexAndHead;
|
mode = Mode::IndexAndHead;
|
||||||
committed_text = None;
|
committed_text = None;
|
||||||
staged_text = index_snapshot.as_ref().map(|buffer| buffer.text());
|
staged_text = index_snapshot
|
||||||
|
.as_ref()
|
||||||
|
.map(|buffer| buffer.text().to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
proto::OpenUncommittedDiffResponse {
|
proto::OpenUncommittedDiffResponse {
|
||||||
committed_text,
|
committed_text,
|
||||||
staged_text,
|
staged_text,
|
||||||
mode: mode.into(),
|
mode: mode as i32,
|
||||||
}
|
}
|
||||||
})
|
})?)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_update_diff_bases(
|
async fn handle_update_diff_bases(
|
||||||
|
@ -2842,9 +2848,15 @@ impl Repository {
|
||||||
.filter_map(|(buffer_id, diff_state)| {
|
.filter_map(|(buffer_id, diff_state)| {
|
||||||
let buffer_store = git_store.buffer_store.read(cx);
|
let buffer_store = git_store.buffer_store.read(cx);
|
||||||
let buffer = buffer_store.get(*buffer_id)?;
|
let buffer = buffer_store.get(*buffer_id)?;
|
||||||
let file = File::from_dyn(buffer.read(cx).file())?;
|
let (worktree, path) = {
|
||||||
let abs_path =
|
let buffer_ref = buffer.read(cx);
|
||||||
file.worktree.read(cx).absolutize(&file.path).ok()?;
|
let file = File::from_dyn(buffer_ref.file())?;
|
||||||
|
(file.worktree.clone(), file.path.clone())
|
||||||
|
};
|
||||||
|
let abs_path = {
|
||||||
|
let worktree_ref = worktree.read(cx);
|
||||||
|
worktree_ref.absolutize(&path).ok()?
|
||||||
|
};
|
||||||
let repo_path = this.abs_path_to_repo_path(&abs_path)?;
|
let repo_path = this.abs_path_to_repo_path(&abs_path)?;
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"start reload diff bases for repo path {}",
|
"start reload diff bases for repo path {}",
|
||||||
|
@ -3066,18 +3078,21 @@ impl Repository {
|
||||||
|
|
||||||
pub fn repo_path_to_project_path(&self, path: &RepoPath, cx: &App) -> Option<ProjectPath> {
|
pub fn repo_path_to_project_path(&self, path: &RepoPath, cx: &App) -> Option<ProjectPath> {
|
||||||
let git_store = self.git_store.upgrade()?;
|
let git_store = self.git_store.upgrade()?;
|
||||||
let worktree_store = git_store.read(cx).worktree_store.read(cx);
|
let git_store_ref = git_store.read(cx);
|
||||||
|
let worktree_store = git_store_ref.worktree_store.read(cx);
|
||||||
let abs_path = self.snapshot.work_directory_abs_path.join(&path.0);
|
let abs_path = self.snapshot.work_directory_abs_path.join(&path.0);
|
||||||
let (worktree, relative_path) = worktree_store.find_worktree(abs_path, cx)?;
|
let (worktree, relative_path) = worktree_store.find_worktree(abs_path, cx)?;
|
||||||
|
let worktree_id = worktree.read(cx).id();
|
||||||
Some(ProjectPath {
|
Some(ProjectPath {
|
||||||
worktree_id: worktree.read(cx).id(),
|
worktree_id,
|
||||||
path: relative_path.into(),
|
path: relative_path.into(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn project_path_to_repo_path(&self, path: &ProjectPath, cx: &App) -> Option<RepoPath> {
|
pub fn project_path_to_repo_path(&self, path: &ProjectPath, cx: &App) -> Option<RepoPath> {
|
||||||
let git_store = self.git_store.upgrade()?;
|
let git_store = self.git_store.upgrade()?;
|
||||||
let worktree_store = git_store.read(cx).worktree_store.read(cx);
|
let git_store_ref = git_store.read(cx);
|
||||||
|
let worktree_store = git_store_ref.worktree_store.read(cx);
|
||||||
let abs_path = worktree_store.absolutize(path, cx)?;
|
let abs_path = worktree_store.absolutize(path, cx)?;
|
||||||
self.snapshot.abs_path_to_repo_path(&abs_path)
|
self.snapshot.abs_path_to_repo_path(&abs_path)
|
||||||
}
|
}
|
||||||
|
|
|
@ -641,7 +641,7 @@ mod tests {
|
||||||
conflict_set.update(cx, |conflict_set, cx| {
|
conflict_set.update(cx, |conflict_set, cx| {
|
||||||
let conflict_range = conflict_set.snapshot().conflicts[0]
|
let conflict_range = conflict_set.snapshot().conflicts[0]
|
||||||
.range
|
.range
|
||||||
.to_point(buffer.read(cx));
|
.to_point(&buffer.read(cx).snapshot());
|
||||||
assert_eq!(conflict_range, Point::new(1, 0)..Point::new(6, 0));
|
assert_eq!(conflict_range, Point::new(1, 0)..Point::new(6, 0));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -673,7 +673,7 @@ mod tests {
|
||||||
conflict_set.update(cx, |conflict_set, cx| {
|
conflict_set.update(cx, |conflict_set, cx| {
|
||||||
let conflict_range = conflict_set.snapshot().conflicts[0]
|
let conflict_range = conflict_set.snapshot().conflicts[0]
|
||||||
.range
|
.range
|
||||||
.to_point(buffer.read(cx));
|
.to_point(&buffer.read(cx).snapshot());
|
||||||
assert_eq!(conflict_range, Point::new(1, 0)..Point::new(6, 0));
|
assert_eq!(conflict_range, Point::new(1, 0)..Point::new(6, 0));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -710,11 +710,11 @@ mod tests {
|
||||||
cx.executor().run_until_parked();
|
cx.executor().run_until_parked();
|
||||||
|
|
||||||
let (old_entry_ids, old_mtimes) = project.read_with(cx, |project, cx| {
|
let (old_entry_ids, old_mtimes) = project.read_with(cx, |project, cx| {
|
||||||
let tree = project.worktrees(cx).next().unwrap().read(cx);
|
let worktree = project.worktrees(cx).next().unwrap();
|
||||||
(
|
let tree = worktree.read(cx);
|
||||||
tree.entries(true, 0).map(|e| e.id).collect::<Vec<_>>(),
|
let entry_ids = tree.entries(true, 0).map(|e| e.id).collect::<Vec<_>>();
|
||||||
tree.entries(true, 0).map(|e| e.mtime).collect::<Vec<_>>(),
|
let mtimes = tree.entries(true, 0).map(|e| e.mtime).collect::<Vec<_>>();
|
||||||
)
|
(entry_ids, mtimes)
|
||||||
});
|
});
|
||||||
|
|
||||||
// Regression test: after the directory is scanned, touch the git repo's
|
// Regression test: after the directory is scanned, touch the git repo's
|
||||||
|
@ -724,11 +724,11 @@ mod tests {
|
||||||
cx.executor().run_until_parked();
|
cx.executor().run_until_parked();
|
||||||
|
|
||||||
let (new_entry_ids, new_mtimes) = project.read_with(cx, |project, cx| {
|
let (new_entry_ids, new_mtimes) = project.read_with(cx, |project, cx| {
|
||||||
let tree = project.worktrees(cx).next().unwrap().read(cx);
|
let worktree = project.worktrees(cx).next().unwrap();
|
||||||
(
|
let tree = worktree.read(cx);
|
||||||
tree.entries(true, 0).map(|e| e.id).collect::<Vec<_>>(),
|
let entry_ids = tree.entries(true, 0).map(|e| e.id).collect::<Vec<_>>();
|
||||||
tree.entries(true, 0).map(|e| e.mtime).collect::<Vec<_>>(),
|
let mtimes = tree.entries(true, 0).map(|e| e.mtime).collect::<Vec<_>>();
|
||||||
)
|
(entry_ids, mtimes)
|
||||||
});
|
});
|
||||||
assert_eq!(new_entry_ids, old_entry_ids);
|
assert_eq!(new_entry_ids, old_entry_ids);
|
||||||
assert_ne!(new_mtimes, old_mtimes);
|
assert_ne!(new_mtimes, old_mtimes);
|
||||||
|
|
|
@ -1151,7 +1151,7 @@ pub async fn location_links_from_lsp(
|
||||||
let target_end =
|
let target_end =
|
||||||
target_buffer.clip_point_utf16(point_from_lsp(target_range.end), Bias::Left);
|
target_buffer.clip_point_utf16(point_from_lsp(target_range.end), Bias::Left);
|
||||||
let target_location = Location {
|
let target_location = Location {
|
||||||
buffer: target_buffer_handle,
|
buffer: target_buffer_handle.clone(),
|
||||||
range: target_buffer.anchor_after(target_start)
|
range: target_buffer.anchor_after(target_start)
|
||||||
..target_buffer.anchor_before(target_end),
|
..target_buffer.anchor_before(target_end),
|
||||||
};
|
};
|
||||||
|
@ -1212,7 +1212,7 @@ pub async fn location_link_from_lsp(
|
||||||
let target_end =
|
let target_end =
|
||||||
target_buffer.clip_point_utf16(point_from_lsp(target_range.end), Bias::Left);
|
target_buffer.clip_point_utf16(point_from_lsp(target_range.end), Bias::Left);
|
||||||
let target_location = Location {
|
let target_location = Location {
|
||||||
buffer: target_buffer_handle,
|
buffer: target_buffer_handle.clone(),
|
||||||
range: target_buffer.anchor_after(target_start)
|
range: target_buffer.anchor_after(target_start)
|
||||||
..target_buffer.anchor_before(target_end),
|
..target_buffer.anchor_before(target_end),
|
||||||
};
|
};
|
||||||
|
|
|
@ -2276,10 +2276,9 @@ impl LocalLspStore {
|
||||||
|
|
||||||
let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
|
let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
|
||||||
|
|
||||||
let edits_since_save = std::cell::LazyCell::new(|| {
|
|
||||||
let saved_version = buffer.read(cx).saved_version();
|
let saved_version = buffer.read(cx).saved_version();
|
||||||
Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
|
let edits: Vec<_> = snapshot.edits_since::<PointUtf16>(saved_version).collect();
|
||||||
});
|
let edits_since_save = Patch::new(edits);
|
||||||
|
|
||||||
let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
|
let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
|
||||||
|
|
||||||
|
@ -2292,8 +2291,8 @@ impl LocalLspStore {
|
||||||
// any unsaved edits.
|
// any unsaved edits.
|
||||||
// Do not alter the reused ones though, as their coordinates were stored as anchors
|
// Do not alter the reused ones though, as their coordinates were stored as anchors
|
||||||
// and were properly adjusted on reuse.
|
// and were properly adjusted on reuse.
|
||||||
start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
|
start = Unclipped(edits_since_save.old_to_new(entry.range.start.0));
|
||||||
end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
|
end = Unclipped(edits_since_save.old_to_new(entry.range.end.0));
|
||||||
} else {
|
} else {
|
||||||
start = entry.range.start;
|
start = entry.range.start;
|
||||||
end = entry.range.end;
|
end = entry.range.end;
|
||||||
|
@ -2318,7 +2317,6 @@ impl LocalLspStore {
|
||||||
diagnostic: entry.diagnostic,
|
diagnostic: entry.diagnostic,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
drop(edits_since_save);
|
|
||||||
|
|
||||||
let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
|
let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
|
||||||
buffer.update(cx, |buffer, cx| {
|
buffer.update(cx, |buffer, cx| {
|
||||||
|
@ -3228,17 +3226,23 @@ impl LocalLspStore {
|
||||||
watchers: impl Iterator<Item = &'a FileSystemWatcher>,
|
watchers: impl Iterator<Item = &'a FileSystemWatcher>,
|
||||||
cx: &mut Context<LspStore>,
|
cx: &mut Context<LspStore>,
|
||||||
) -> LanguageServerWatchedPathsBuilder {
|
) -> LanguageServerWatchedPathsBuilder {
|
||||||
let worktrees = self
|
let worktree_ids = self
|
||||||
.worktree_store
|
.worktree_store
|
||||||
.read(cx)
|
.read(cx)
|
||||||
.worktrees()
|
.worktrees()
|
||||||
.filter_map(|worktree| {
|
.filter_map(|worktree| {
|
||||||
self.language_servers_for_worktree(worktree.read(cx).id())
|
let worktree_id = worktree.read(cx).id();
|
||||||
|
self.language_servers_for_worktree(worktree_id)
|
||||||
.find(|server| server.server_id() == language_server_id)
|
.find(|server| server.server_id() == language_server_id)
|
||||||
.map(|_| worktree)
|
.map(|_| worktree_id)
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let worktrees = worktree_ids
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|id| self.worktree_store.read(cx).worktree_for_id(id, cx))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let mut worktree_globs = HashMap::default();
|
let mut worktree_globs = HashMap::default();
|
||||||
let mut abs_globs = HashMap::default();
|
let mut abs_globs = HashMap::default();
|
||||||
log::trace!(
|
log::trace!(
|
||||||
|
@ -3819,7 +3823,7 @@ impl LspStore {
|
||||||
request: R,
|
request: R,
|
||||||
cx: &mut Context<LspStore>,
|
cx: &mut Context<LspStore>,
|
||||||
) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
|
) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
|
||||||
let message = request.to_proto(upstream_project_id, buffer.read(cx));
|
let message = request.to_proto(upstream_project_id, &*buffer.read(cx));
|
||||||
cx.spawn(async move |this, cx| {
|
cx.spawn(async move |this, cx| {
|
||||||
let response = client.request(message).await?;
|
let response = client.request(message).await?;
|
||||||
let this = this.upgrade().context("project dropped")?;
|
let this = this.upgrade().context("project dropped")?;
|
||||||
|
@ -4127,7 +4131,10 @@ impl LspStore {
|
||||||
ignore_refcounts: bool,
|
ignore_refcounts: bool,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> OpenLspBufferHandle {
|
) -> OpenLspBufferHandle {
|
||||||
let buffer_id = buffer.read(cx).remote_id();
|
let buffer_id = {
|
||||||
|
let buffer_ref = buffer.read(cx);
|
||||||
|
buffer_ref.remote_id()
|
||||||
|
};
|
||||||
let handle = cx.new(|_| buffer.clone());
|
let handle = cx.new(|_| buffer.clone());
|
||||||
if let Some(local) = self.as_local_mut() {
|
if let Some(local) = self.as_local_mut() {
|
||||||
let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
|
let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
|
||||||
|
@ -4139,7 +4146,8 @@ impl LspStore {
|
||||||
// When a new unnamed buffer is created and saved, we will start loading it's language. Once the language is loaded, we go over all "language-less" buffers and try to fit that new language
|
// When a new unnamed buffer is created and saved, we will start loading it's language. Once the language is loaded, we go over all "language-less" buffers and try to fit that new language
|
||||||
// with them. However, we do that only for the buffers that we think are open in at least one editor; thus, we need to keep tab of unnamed buffers as well, even though they're not actually registered with any language
|
// with them. However, we do that only for the buffers that we think are open in at least one editor; thus, we need to keep tab of unnamed buffers as well, even though they're not actually registered with any language
|
||||||
// servers in practice (we don't support non-file URI schemes in our LSP impl).
|
// servers in practice (we don't support non-file URI schemes in our LSP impl).
|
||||||
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 handle;
|
return handle;
|
||||||
};
|
};
|
||||||
if !file.is_local() {
|
if !file.is_local() {
|
||||||
|
@ -4258,12 +4266,18 @@ impl LspStore {
|
||||||
let mut plain_text_buffers = Vec::new();
|
let mut plain_text_buffers = Vec::new();
|
||||||
let mut buffers_with_unknown_injections = Vec::new();
|
let mut buffers_with_unknown_injections = Vec::new();
|
||||||
for handle in this.buffer_store.read(cx).buffers() {
|
for handle in this.buffer_store.read(cx).buffers() {
|
||||||
|
let should_push_plain_text = {
|
||||||
let buffer = handle.read(cx);
|
let buffer = handle.read(cx);
|
||||||
if buffer.language().is_none()
|
buffer.language().is_none()
|
||||||
|| buffer.language() == Some(&*language::PLAIN_TEXT)
|
|| buffer.language() == Some(&*language::PLAIN_TEXT)
|
||||||
{
|
};
|
||||||
|
let contains_unknown_injections = {
|
||||||
|
let buffer = handle.read(cx);
|
||||||
|
buffer.contains_unknown_injections()
|
||||||
|
};
|
||||||
|
if should_push_plain_text {
|
||||||
plain_text_buffers.push(handle);
|
plain_text_buffers.push(handle);
|
||||||
} else if buffer.contains_unknown_injections() {
|
} else if contains_unknown_injections {
|
||||||
buffers_with_unknown_injections.push(handle);
|
buffers_with_unknown_injections.push(handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4475,6 +4489,7 @@ impl LspStore {
|
||||||
return Task::ready(Ok(Default::default()));
|
return Task::ready(Ok(Default::default()));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let (abs_path, lsp_params, status) = {
|
||||||
let buffer = buffer_handle.read(cx);
|
let buffer = buffer_handle.read(cx);
|
||||||
let file = File::from_dyn(buffer.file()).and_then(File::as_local);
|
let file = File::from_dyn(buffer.file()).and_then(File::as_local);
|
||||||
|
|
||||||
|
@ -4482,9 +4497,10 @@ impl LspStore {
|
||||||
return Task::ready(Ok(Default::default()));
|
return Task::ready(Ok(Default::default()));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let abs_path = file.abs_path(cx);
|
||||||
let lsp_params = match request.to_lsp_params_or_response(
|
let lsp_params = match request.to_lsp_params_or_response(
|
||||||
&file.abs_path(cx),
|
&abs_path,
|
||||||
buffer,
|
&*buffer,
|
||||||
&language_server,
|
&language_server,
|
||||||
cx,
|
cx,
|
||||||
) {
|
) {
|
||||||
|
@ -4504,6 +4520,8 @@ impl LspStore {
|
||||||
};
|
};
|
||||||
|
|
||||||
let status = request.status();
|
let status = request.status();
|
||||||
|
(_abs_path, lsp_params, status)
|
||||||
|
};
|
||||||
if !request.check_capabilities(language_server.adapter_server_capabilities()) {
|
if !request.check_capabilities(language_server.adapter_server_capabilities()) {
|
||||||
return Task::ready(Ok(Default::default()));
|
return Task::ready(Ok(Default::default()));
|
||||||
}
|
}
|
||||||
|
@ -5188,7 +5206,7 @@ impl LspStore {
|
||||||
})?
|
})?
|
||||||
.await?;
|
.await?;
|
||||||
this.update(cx, |this, cx| {
|
this.update(cx, |this, cx| {
|
||||||
let position = position.to_point_utf16(buffer.read(cx));
|
let position = position.to_point_utf16(&buffer.read(cx).snapshot());
|
||||||
this.on_type_format(buffer, position, trigger, false, cx)
|
this.on_type_format(buffer, position, trigger, false, cx)
|
||||||
})?
|
})?
|
||||||
.await
|
.await
|
||||||
|
@ -5206,7 +5224,7 @@ impl LspStore {
|
||||||
push_to_history: bool,
|
push_to_history: bool,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Task<Result<Option<Transaction>>> {
|
) -> Task<Result<Option<Transaction>>> {
|
||||||
let position = position.to_point_utf16(buffer.read(cx));
|
let position = position.to_point_utf16(&buffer.read(cx).snapshot());
|
||||||
self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
|
self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5269,7 +5287,7 @@ impl LspStore {
|
||||||
proto::AllLanguageServers {},
|
proto::AllLanguageServers {},
|
||||||
)),
|
)),
|
||||||
request: Some(proto::multi_lsp_query::Request::GetDefinition(
|
request: Some(proto::multi_lsp_query::Request::GetDefinition(
|
||||||
GetDefinitions { position }.to_proto(project_id, buffer_handle.read(cx)),
|
GetDefinitions { position }.to_proto(project_id, &*buffer_handle.read(cx)),
|
||||||
)),
|
)),
|
||||||
});
|
});
|
||||||
let buffer = buffer_handle.clone();
|
let buffer = buffer_handle.clone();
|
||||||
|
@ -5342,7 +5360,7 @@ impl LspStore {
|
||||||
proto::AllLanguageServers {},
|
proto::AllLanguageServers {},
|
||||||
)),
|
)),
|
||||||
request: Some(proto::multi_lsp_query::Request::GetDeclaration(
|
request: Some(proto::multi_lsp_query::Request::GetDeclaration(
|
||||||
GetDeclarations { position }.to_proto(project_id, buffer_handle.read(cx)),
|
GetDeclarations { position }.to_proto(project_id, &*buffer_handle.read(cx)),
|
||||||
)),
|
)),
|
||||||
});
|
});
|
||||||
let buffer = buffer_handle.clone();
|
let buffer = buffer_handle.clone();
|
||||||
|
@ -5415,7 +5433,7 @@ impl LspStore {
|
||||||
proto::AllLanguageServers {},
|
proto::AllLanguageServers {},
|
||||||
)),
|
)),
|
||||||
request: Some(proto::multi_lsp_query::Request::GetTypeDefinition(
|
request: Some(proto::multi_lsp_query::Request::GetTypeDefinition(
|
||||||
GetTypeDefinitions { position }.to_proto(project_id, buffer_handle.read(cx)),
|
GetTypeDefinitions { position }.to_proto(project_id, &*buffer_handle.read(cx)),
|
||||||
)),
|
)),
|
||||||
});
|
});
|
||||||
let buffer = buffer_handle.clone();
|
let buffer = buffer_handle.clone();
|
||||||
|
@ -5488,7 +5506,7 @@ impl LspStore {
|
||||||
proto::AllLanguageServers {},
|
proto::AllLanguageServers {},
|
||||||
)),
|
)),
|
||||||
request: Some(proto::multi_lsp_query::Request::GetImplementation(
|
request: Some(proto::multi_lsp_query::Request::GetImplementation(
|
||||||
GetImplementations { position }.to_proto(project_id, buffer_handle.read(cx)),
|
GetImplementations { position }.to_proto(project_id, &*buffer_handle.read(cx)),
|
||||||
)),
|
)),
|
||||||
});
|
});
|
||||||
let buffer = buffer_handle.clone();
|
let buffer = buffer_handle.clone();
|
||||||
|
@ -5561,7 +5579,7 @@ impl LspStore {
|
||||||
proto::AllLanguageServers {},
|
proto::AllLanguageServers {},
|
||||||
)),
|
)),
|
||||||
request: Some(proto::multi_lsp_query::Request::GetReferences(
|
request: Some(proto::multi_lsp_query::Request::GetReferences(
|
||||||
GetReferences { position }.to_proto(project_id, buffer_handle.read(cx)),
|
GetReferences { position }.to_proto(project_id, &*buffer_handle.read(cx)),
|
||||||
)),
|
)),
|
||||||
});
|
});
|
||||||
let buffer = buffer_handle.clone();
|
let buffer = buffer_handle.clone();
|
||||||
|
@ -5639,7 +5657,7 @@ impl LspStore {
|
||||||
range: range.clone(),
|
range: range.clone(),
|
||||||
kinds: kinds.clone(),
|
kinds: kinds.clone(),
|
||||||
}
|
}
|
||||||
.to_proto(project_id, buffer_handle.read(cx)),
|
.to_proto(project_id, &*buffer_handle.read(cx)),
|
||||||
)),
|
)),
|
||||||
});
|
});
|
||||||
let buffer = buffer_handle.clone();
|
let buffer = buffer_handle.clone();
|
||||||
|
@ -5716,7 +5734,7 @@ impl LspStore {
|
||||||
proto::AllLanguageServers {},
|
proto::AllLanguageServers {},
|
||||||
)),
|
)),
|
||||||
request: Some(proto::multi_lsp_query::Request::GetCodeLens(
|
request: Some(proto::multi_lsp_query::Request::GetCodeLens(
|
||||||
GetCodeLens.to_proto(project_id, buffer_handle.read(cx)),
|
GetCodeLens.to_proto(project_id, &*buffer_handle.read(cx)),
|
||||||
)),
|
)),
|
||||||
});
|
});
|
||||||
let buffer = buffer_handle.clone();
|
let buffer = buffer_handle.clone();
|
||||||
|
@ -6278,8 +6296,7 @@ impl LspStore {
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Task<Result<Option<Transaction>>> {
|
) -> Task<Result<Option<Transaction>>> {
|
||||||
if let Some((client, project_id)) = self.upstream_client() {
|
if let Some((client, project_id)) = self.upstream_client() {
|
||||||
let buffer = buffer_handle.read(cx);
|
let buffer_id = buffer_handle.read(cx).remote_id();
|
||||||
let buffer_id = buffer.remote_id();
|
|
||||||
cx.spawn(async move |_, cx| {
|
cx.spawn(async move |_, cx| {
|
||||||
let request = {
|
let request = {
|
||||||
let completion = completions.borrow()[completion_index].clone();
|
let completion = completions.borrow()[completion_index].clone();
|
||||||
|
@ -6482,6 +6499,7 @@ impl LspStore {
|
||||||
end: Some(serialize_anchor(&range_end)),
|
end: Some(serialize_anchor(&range_end)),
|
||||||
version: serialize_version(&buffer_handle.read(cx).version()),
|
version: serialize_version(&buffer_handle.read(cx).version()),
|
||||||
};
|
};
|
||||||
|
let buffer_handle_clone = buffer_handle.clone();
|
||||||
cx.spawn(async move |project, cx| {
|
cx.spawn(async move |project, cx| {
|
||||||
let response = client
|
let response = client
|
||||||
.request(request)
|
.request(request)
|
||||||
|
@ -6491,13 +6509,14 @@ impl LspStore {
|
||||||
lsp_request,
|
lsp_request,
|
||||||
response,
|
response,
|
||||||
project.upgrade().context("No project")?,
|
project.upgrade().context("No project")?,
|
||||||
buffer_handle.clone(),
|
buffer_handle_clone,
|
||||||
cx.clone(),
|
cx.clone(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.context("inlay hints proto response conversion")
|
.context("inlay hints proto response conversion")
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
let buffer_handle_for_task = buffer_handle.clone();
|
||||||
let lsp_request_task = self.request_lsp(
|
let lsp_request_task = self.request_lsp(
|
||||||
buffer_handle.clone(),
|
buffer_handle.clone(),
|
||||||
LanguageServerToQuery::FirstCapable,
|
LanguageServerToQuery::FirstCapable,
|
||||||
|
@ -6505,7 +6524,7 @@ impl LspStore {
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
cx.spawn(async move |_, cx| {
|
cx.spawn(async move |_, cx| {
|
||||||
buffer_handle
|
buffer_handle_for_task
|
||||||
.update(cx, |buffer, _| {
|
.update(cx, |buffer, _| {
|
||||||
buffer.wait_for_edits(vec![range_start.timestamp, range_end.timestamp])
|
buffer.wait_for_edits(vec![range_start.timestamp, range_end.timestamp])
|
||||||
})?
|
})?
|
||||||
|
@ -6729,17 +6748,20 @@ impl LspStore {
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Task<anyhow::Result<HashMap<LanguageServerId, HashSet<DocumentColor>>>> {
|
) -> Task<anyhow::Result<HashMap<LanguageServerId, HashSet<DocumentColor>>>> {
|
||||||
if let Some((client, project_id)) = self.upstream_client() {
|
if let Some((client, project_id)) = self.upstream_client() {
|
||||||
let request_task = client.request(proto::MultiLspQuery {
|
let request_task = {
|
||||||
|
let buffer_ref = buffer.read(cx);
|
||||||
|
client.request(proto::MultiLspQuery {
|
||||||
project_id,
|
project_id,
|
||||||
buffer_id: buffer.read(cx).remote_id().to_proto(),
|
buffer_id: buffer_ref.remote_id().to_proto(),
|
||||||
version: serialize_version(&buffer.read(cx).version()),
|
version: serialize_version(&buffer_ref.version()),
|
||||||
strategy: Some(proto::multi_lsp_query::Strategy::All(
|
strategy: Some(proto::multi_lsp_query::Strategy::All(
|
||||||
proto::AllLanguageServers {},
|
proto::AllLanguageServers {},
|
||||||
)),
|
)),
|
||||||
request: Some(proto::multi_lsp_query::Request::GetDocumentColor(
|
request: Some(proto::multi_lsp_query::Request::GetDocumentColor(
|
||||||
GetDocumentColor {}.to_proto(project_id, buffer.read(cx)),
|
GetDocumentColor.to_proto(project_id, &*buffer_ref),
|
||||||
)),
|
)),
|
||||||
});
|
})
|
||||||
|
};
|
||||||
cx.spawn(async move |project, cx| {
|
cx.spawn(async move |project, cx| {
|
||||||
let Some(project) = project.upgrade() else {
|
let Some(project) = project.upgrade() else {
|
||||||
return Ok(HashMap::default());
|
return Ok(HashMap::default());
|
||||||
|
@ -6808,7 +6830,7 @@ impl LspStore {
|
||||||
position: T,
|
position: T,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Task<Vec<SignatureHelp>> {
|
) -> Task<Vec<SignatureHelp>> {
|
||||||
let position = position.to_point_utf16(buffer.read(cx));
|
let position = position.to_point_utf16(&buffer.read(cx).snapshot());
|
||||||
|
|
||||||
if let Some((client, upstream_project_id)) = self.upstream_client() {
|
if let Some((client, upstream_project_id)) = self.upstream_client() {
|
||||||
let request_task = client.request(proto::MultiLspQuery {
|
let request_task = client.request(proto::MultiLspQuery {
|
||||||
|
@ -6819,7 +6841,7 @@ impl LspStore {
|
||||||
proto::AllLanguageServers {},
|
proto::AllLanguageServers {},
|
||||||
)),
|
)),
|
||||||
request: Some(proto::multi_lsp_query::Request::GetSignatureHelp(
|
request: Some(proto::multi_lsp_query::Request::GetSignatureHelp(
|
||||||
GetSignatureHelp { position }.to_proto(upstream_project_id, buffer.read(cx)),
|
GetSignatureHelp { position }.to_proto(upstream_project_id, &*buffer.read(cx)),
|
||||||
)),
|
)),
|
||||||
});
|
});
|
||||||
let buffer = buffer.clone();
|
let buffer = buffer.clone();
|
||||||
|
@ -6890,7 +6912,7 @@ impl LspStore {
|
||||||
proto::AllLanguageServers {},
|
proto::AllLanguageServers {},
|
||||||
)),
|
)),
|
||||||
request: Some(proto::multi_lsp_query::Request::GetHover(
|
request: Some(proto::multi_lsp_query::Request::GetHover(
|
||||||
GetHover { position }.to_proto(upstream_project_id, buffer.read(cx)),
|
GetHover { position }.to_proto(upstream_project_id, &*buffer.read(cx)),
|
||||||
)),
|
)),
|
||||||
});
|
});
|
||||||
let buffer = buffer.clone();
|
let buffer = buffer.clone();
|
||||||
|
@ -7141,41 +7163,49 @@ impl LspStore {
|
||||||
summary
|
summary
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pub fn diagnostic_summaries<'a>(
|
||||||
|
// &'a self,
|
||||||
|
// include_ignored: bool,
|
||||||
|
// cx: &'a App,
|
||||||
|
// ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
|
||||||
|
// self.worktree_store
|
||||||
|
// .read(cx)
|
||||||
|
// .visible_worktrees(cx)
|
||||||
|
// .filter_map(|worktree| {
|
||||||
|
// let worktree = worktree.read(cx);
|
||||||
|
// Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
|
||||||
|
// })
|
||||||
|
// .flat_map(move |(worktree, summaries)| {
|
||||||
|
// let worktree_id = worktree.id();
|
||||||
|
// summaries
|
||||||
|
// .iter()
|
||||||
|
// .filter(move |(path, _)| {
|
||||||
|
// include_ignored
|
||||||
|
// || worktree
|
||||||
|
// .entry_for_path(path.as_ref())
|
||||||
|
// .map_or(false, |entry| !entry.is_ignored)
|
||||||
|
// })
|
||||||
|
// .flat_map(move |(path, summaries)| {
|
||||||
|
// summaries.iter().map(move |(server_id, summary)| {
|
||||||
|
// (
|
||||||
|
// ProjectPath {
|
||||||
|
// worktree_id,
|
||||||
|
// path: path.clone(),
|
||||||
|
// },
|
||||||
|
// *server_id,
|
||||||
|
// *summary,
|
||||||
|
// )
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
// }
|
||||||
pub fn diagnostic_summaries<'a>(
|
pub fn diagnostic_summaries<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
include_ignored: bool,
|
include_ignored: bool,
|
||||||
cx: &'a App,
|
cx: &'a App,
|
||||||
) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
|
) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
|
||||||
self.worktree_store
|
// todo!("diagnostic_summaries needs to be refactored to handle Ref type")
|
||||||
.read(cx)
|
std::iter::empty()
|
||||||
.visible_worktrees(cx)
|
|
||||||
.filter_map(|worktree| {
|
|
||||||
let worktree = worktree.read(cx);
|
|
||||||
Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
|
|
||||||
})
|
|
||||||
.flat_map(move |(worktree, summaries)| {
|
|
||||||
let worktree_id = worktree.id();
|
|
||||||
summaries
|
|
||||||
.iter()
|
|
||||||
.filter(move |(path, _)| {
|
|
||||||
include_ignored
|
|
||||||
|| worktree
|
|
||||||
.entry_for_path(path.as_ref())
|
|
||||||
.map_or(false, |entry| !entry.is_ignored)
|
|
||||||
})
|
|
||||||
.flat_map(move |(path, summaries)| {
|
|
||||||
summaries.iter().map(move |(server_id, summary)| {
|
|
||||||
(
|
|
||||||
ProjectPath {
|
|
||||||
worktree_id,
|
|
||||||
path: path.clone(),
|
|
||||||
},
|
|
||||||
*server_id,
|
|
||||||
*summary,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_buffer_edited(
|
pub fn on_buffer_edited(
|
||||||
|
@ -7288,7 +7318,8 @@ impl LspStore {
|
||||||
buffer: Entity<Buffer>,
|
buffer: Entity<Buffer>,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
let file = File::from_dyn(buffer.read(cx).file())?;
|
let buffer_ref = buffer.read(cx);
|
||||||
|
let file = File::from_dyn(buffer_ref.file())?;
|
||||||
let worktree_id = file.worktree_id(cx);
|
let worktree_id = file.worktree_id(cx);
|
||||||
let abs_path = file.as_local()?.abs_path(cx);
|
let abs_path = file.as_local()?.abs_path(cx);
|
||||||
let text_document = lsp::TextDocumentIdentifier {
|
let text_document = lsp::TextDocumentIdentifier {
|
||||||
|
@ -7610,7 +7641,8 @@ impl LspStore {
|
||||||
path: relative_path.into(),
|
path: relative_path.into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
|
let buffer_handle = self.buffer_store.read(cx).get_by_path(&project_path);
|
||||||
|
if let Some(buffer_handle) = buffer_handle {
|
||||||
let snapshot = buffer_handle.read(cx).snapshot();
|
let snapshot = buffer_handle.read(cx).snapshot();
|
||||||
let buffer = buffer_handle.read(cx);
|
let buffer = buffer_handle.read(cx);
|
||||||
let reused_diagnostics = buffer
|
let reused_diagnostics = buffer
|
||||||
|
@ -7618,7 +7650,7 @@ impl LspStore {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|diag| {
|
.flat_map(|diag| {
|
||||||
diag.iter()
|
diag.iter()
|
||||||
.filter(|v| filter(buffer, &v.diagnostic, cx))
|
.filter(|v| filter(&*buffer, &v.diagnostic, cx))
|
||||||
.map(|v| {
|
.map(|v| {
|
||||||
let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
|
let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
|
||||||
let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
|
let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
|
||||||
|
@ -7629,6 +7661,7 @@ impl LspStore {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
drop(buffer);
|
||||||
|
|
||||||
self.as_local_mut()
|
self.as_local_mut()
|
||||||
.context("cannot merge diagnostics on a remote LspStore")?
|
.context("cannot merge diagnostics on a remote LspStore")?
|
||||||
|
@ -8570,12 +8603,8 @@ impl LspStore {
|
||||||
.read(cx)
|
.read(cx)
|
||||||
.worktree_and_entry_for_id(entry_id, cx)
|
.worktree_and_entry_for_id(entry_id, cx)
|
||||||
.map(|(worktree, entry)| {
|
.map(|(worktree, entry)| {
|
||||||
(
|
let worktree_id = worktree.read(cx).id();
|
||||||
worktree.read(cx).id(),
|
(worktree_id, worktree, entry.path.clone(), entry.is_dir())
|
||||||
worktree,
|
|
||||||
entry.path.clone(),
|
|
||||||
entry.is_dir(),
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
})?
|
})?
|
||||||
.context("worktree not found")?;
|
.context("worktree not found")?;
|
||||||
|
@ -9862,11 +9891,14 @@ impl LspStore {
|
||||||
let buffers = buffers
|
let buffers = buffers
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|buffer_handle| {
|
.map(|buffer_handle| {
|
||||||
|
let (buffer_abs_path, remote_id) = {
|
||||||
let buffer = buffer_handle.read(cx);
|
let buffer = buffer_handle.read(cx);
|
||||||
let buffer_abs_path = File::from_dyn(buffer.file())
|
let buffer_abs_path = File::from_dyn(buffer.file())
|
||||||
.and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
|
.and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
|
||||||
|
(buffer_abs_path, buffer.remote_id())
|
||||||
|
};
|
||||||
|
|
||||||
(buffer_handle, buffer_abs_path, buffer.remote_id())
|
(buffer_handle, buffer_abs_path, remote_id)
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
@ -10393,21 +10425,24 @@ impl LspStore {
|
||||||
cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
|
cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
|
// fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
|
||||||
let (worktree, relative_path) =
|
// let (worktree, relative_path) =
|
||||||
self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
|
// self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
|
||||||
|
|
||||||
let project_path = ProjectPath {
|
// let project_path = ProjectPath {
|
||||||
worktree_id: worktree.read(cx).id(),
|
// worktree_id: worktree.read(cx).id(),
|
||||||
path: relative_path.into(),
|
// path: relative_path.into(),
|
||||||
};
|
// };
|
||||||
|
|
||||||
Some(
|
// Some(
|
||||||
self.buffer_store()
|
// self.buffer_store()
|
||||||
.read(cx)
|
// .read(cx)
|
||||||
.get_by_path(&project_path)?
|
// .get_by_path(&project_path)?
|
||||||
.read(cx),
|
// .read(cx),
|
||||||
)
|
// )
|
||||||
|
// }
|
||||||
|
fn get_buffer<'a>(&self, _abs_path: &Path, _cx: &'a App) -> Option<&'a Buffer> {
|
||||||
|
todo!("get_buffer needs to be refactored to handle Ref type")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_diagnostics(
|
pub fn update_diagnostics(
|
||||||
|
@ -11239,12 +11274,10 @@ impl LspStore {
|
||||||
buffer_id: BufferId,
|
buffer_id: BufferId,
|
||||||
cx: &App,
|
cx: &App,
|
||||||
) -> Option<String> {
|
) -> Option<String> {
|
||||||
let abs_path = self
|
let abs_path = self.buffer_store.read(cx).get(buffer_id).and_then(|b| {
|
||||||
.buffer_store
|
let buffer_ref = b.read(cx);
|
||||||
.read(cx)
|
File::from_dyn(buffer_ref.file()).map(|f| f.abs_path(cx).to_path_buf())
|
||||||
.get(buffer_id)
|
})?;
|
||||||
.and_then(|b| File::from_dyn(b.read(cx).file()))
|
|
||||||
.map(|f| f.abs_path(cx))?;
|
|
||||||
self.as_local()?
|
self.as_local()?
|
||||||
.buffer_pull_diagnostics_result_ids
|
.buffer_pull_diagnostics_result_ids
|
||||||
.get(&server_id)?
|
.get(&server_id)?
|
||||||
|
|
|
@ -62,8 +62,8 @@ impl WorktreeRoots {
|
||||||
}
|
}
|
||||||
WorktreeEvent::UpdatedGitRepositories(_) => {}
|
WorktreeEvent::UpdatedGitRepositories(_) => {}
|
||||||
WorktreeEvent::DeletedEntry(entry_id) => {
|
WorktreeEvent::DeletedEntry(entry_id) => {
|
||||||
let Some(entry) = this.worktree_store.read(cx).entry_for_id(*entry_id, cx)
|
let worktree_store = this.worktree_store.read(cx);
|
||||||
else {
|
let Some(entry) = worktree_store.entry_for_id(*entry_id, cx) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let path = TriePath::from(entry.path.as_ref());
|
let path = TriePath::from(entry.path.as_ref());
|
||||||
|
|
|
@ -1740,7 +1740,8 @@ impl Project {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn active_debug_session(&self, cx: &App) -> Option<(Entity<Session>, ActiveStackFrame)> {
|
pub fn active_debug_session(&self, cx: &App) -> Option<(Entity<Session>, 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
|
let session = self
|
||||||
.dap_store
|
.dap_store
|
||||||
.read(cx)
|
.read(cx)
|
||||||
|
@ -1817,11 +1818,18 @@ impl Project {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pub fn shell_environment_errors<'a>(
|
||||||
|
// &'a self,
|
||||||
|
// cx: &'a App,
|
||||||
|
// ) -> impl Iterator<Item = (&'a Arc<Path>, &'a EnvironmentErrorMessage)> {
|
||||||
|
// self.environment.read(cx).environment_errors()
|
||||||
|
// }
|
||||||
pub fn shell_environment_errors<'a>(
|
pub fn shell_environment_errors<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
cx: &'a App,
|
cx: &'a App,
|
||||||
) -> impl Iterator<Item = (&'a Arc<Path>, &'a EnvironmentErrorMessage)> {
|
) -> impl Iterator<Item = (&'a Arc<Path>, &'a EnvironmentErrorMessage)> {
|
||||||
self.environment.read(cx).environment_errors()
|
// todo!("shell_environment_errors needs to be refactored to handle Ref type")
|
||||||
|
std::iter::empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_environment_error(&mut self, abs_path: &Path, cx: &mut Context<Self>) {
|
pub fn remove_environment_error(&mut self, abs_path: &Path, cx: &mut Context<Self>) {
|
||||||
|
@ -1932,20 +1940,36 @@ impl Project {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// /// Collect all worktrees, including ones that don't appear in the project panel
|
||||||
|
// pub fn worktrees<'a>(
|
||||||
|
// &self,
|
||||||
|
// cx: &'a App,
|
||||||
|
// ) -> impl 'a + DoubleEndedIterator<Item = Entity<Worktree>> {
|
||||||
|
// self.worktree_store.read(cx).worktrees()
|
||||||
|
// }
|
||||||
/// Collect all worktrees, including ones that don't appear in the project panel
|
/// Collect all worktrees, including ones that don't appear in the project panel
|
||||||
pub fn worktrees<'a>(
|
pub fn worktrees<'a>(
|
||||||
&self,
|
&self,
|
||||||
cx: &'a App,
|
cx: &'a App,
|
||||||
) -> impl 'a + DoubleEndedIterator<Item = Entity<Worktree>> {
|
) -> impl 'a + DoubleEndedIterator<Item = Entity<Worktree>> {
|
||||||
self.worktree_store.read(cx).worktrees()
|
// todo!("worktrees needs to be refactored to handle Ref type")
|
||||||
|
std::iter::empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// /// Collect all user-visible worktrees, the ones that appear in the project panel.
|
||||||
|
// pub fn visible_worktrees<'a>(
|
||||||
|
// &'a self,
|
||||||
|
// cx: &'a App,
|
||||||
|
// ) -> impl 'a + DoubleEndedIterator<Item = Entity<Worktree>> {
|
||||||
|
// self.worktree_store.read(cx).visible_worktrees(cx)
|
||||||
|
// }
|
||||||
/// Collect all user-visible worktrees, the ones that appear in the project panel.
|
/// Collect all user-visible worktrees, the ones that appear in the project panel.
|
||||||
pub fn visible_worktrees<'a>(
|
pub fn visible_worktrees<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
cx: &'a App,
|
cx: &'a App,
|
||||||
) -> impl 'a + DoubleEndedIterator<Item = Entity<Worktree>> {
|
) -> impl 'a + DoubleEndedIterator<Item = Entity<Worktree>> {
|
||||||
self.worktree_store.read(cx).visible_worktrees(cx)
|
// todo!("visible_worktrees needs to be refactored to handle Ref type")
|
||||||
|
std::iter::empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn worktree_for_root_name(&self, root_name: &str, cx: &App) -> Option<Entity<Worktree>> {
|
pub fn worktree_for_root_name(&self, root_name: &str, cx: &App) -> Option<Entity<Worktree>> {
|
||||||
|
@ -1953,9 +1977,13 @@ impl Project {
|
||||||
.find(|tree| tree.read(cx).root_name() == root_name)
|
.find(|tree| tree.read(cx).root_name() == root_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pub fn worktree_root_names<'a>(&'a self, cx: &'a App) -> impl Iterator<Item = &'a str> {
|
||||||
|
// self.visible_worktrees(cx)
|
||||||
|
// .map(|tree| tree.read(cx).root_name())
|
||||||
|
// }
|
||||||
pub fn worktree_root_names<'a>(&'a self, cx: &'a App) -> impl Iterator<Item = &'a str> {
|
pub fn worktree_root_names<'a>(&'a self, cx: &'a App) -> impl Iterator<Item = &'a str> {
|
||||||
self.visible_worktrees(cx)
|
// todo!("worktree_root_names needs to be refactored to handle Ref type")
|
||||||
.map(|tree| tree.read(cx).root_name())
|
std::iter::empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn worktree_for_id(&self, id: WorktreeId, cx: &App) -> Option<Entity<Worktree>> {
|
pub fn worktree_for_id(&self, id: WorktreeId, cx: &App) -> Option<Entity<Worktree>> {
|
||||||
|
@ -3306,15 +3334,26 @@ impl Project {
|
||||||
.read(cx)
|
.read(cx)
|
||||||
.active_toolchain(path, language_name, cx)
|
.active_toolchain(path, language_name, cx)
|
||||||
}
|
}
|
||||||
|
// pub fn language_server_statuses<'a>(
|
||||||
|
// &'a self,
|
||||||
|
// cx: &'a App,
|
||||||
|
// ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &'a LanguageServerStatus)> {
|
||||||
|
// self.lsp_store.read(cx).language_server_statuses()
|
||||||
|
// }
|
||||||
pub fn language_server_statuses<'a>(
|
pub fn language_server_statuses<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
cx: &'a App,
|
cx: &'a App,
|
||||||
) -> impl DoubleEndedIterator<Item = (LanguageServerId, &'a LanguageServerStatus)> {
|
) -> impl DoubleEndedIterator<Item = (LanguageServerId, &'a LanguageServerStatus)> {
|
||||||
self.lsp_store.read(cx).language_server_statuses()
|
// todo!("language_server_statuses needs to be refactored to handle Ref type")
|
||||||
|
std::iter::empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn last_formatting_failure<'a>(&self, cx: &'a App) -> Option<&'a str> {
|
// pub fn last_formatting_failure<'a>(&self, cx: &'a App) -> Option<&'a str> {
|
||||||
self.lsp_store.read(cx).last_formatting_failure()
|
// self.lsp_store.read(cx).last_formatting_failure()
|
||||||
|
// }
|
||||||
|
pub fn last_formatting_failure<'a>(&self, _cx: &'a App) -> Option<&'a str> {
|
||||||
|
// todo!("last_formatting_failure needs to be refactored to handle Ref type")
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset_last_formatting_failure(&self, cx: &mut App) {
|
pub fn reset_last_formatting_failure(&self, cx: &mut App) {
|
||||||
|
@ -3361,7 +3400,7 @@ impl Project {
|
||||||
position: T,
|
position: T,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Task<Result<Vec<LocationLink>>> {
|
) -> Task<Result<Vec<LocationLink>>> {
|
||||||
let position = position.to_point_utf16(buffer.read(cx));
|
let position = position.to_point_utf16(&buffer.read(cx).snapshot());
|
||||||
self.lsp_store.update(cx, |lsp_store, cx| {
|
self.lsp_store.update(cx, |lsp_store, cx| {
|
||||||
lsp_store.definitions(buffer, position, cx)
|
lsp_store.definitions(buffer, position, cx)
|
||||||
})
|
})
|
||||||
|
@ -3373,7 +3412,7 @@ impl Project {
|
||||||
position: T,
|
position: T,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Task<Result<Vec<LocationLink>>> {
|
) -> Task<Result<Vec<LocationLink>>> {
|
||||||
let position = position.to_point_utf16(buffer.read(cx));
|
let position = position.to_point_utf16(&buffer.read(cx).snapshot());
|
||||||
self.lsp_store.update(cx, |lsp_store, cx| {
|
self.lsp_store.update(cx, |lsp_store, cx| {
|
||||||
lsp_store.declarations(buffer, position, cx)
|
lsp_store.declarations(buffer, position, cx)
|
||||||
})
|
})
|
||||||
|
@ -3385,7 +3424,7 @@ impl Project {
|
||||||
position: T,
|
position: T,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Task<Result<Vec<LocationLink>>> {
|
) -> Task<Result<Vec<LocationLink>>> {
|
||||||
let position = position.to_point_utf16(buffer.read(cx));
|
let position = position.to_point_utf16(&buffer.read(cx).snapshot());
|
||||||
self.lsp_store.update(cx, |lsp_store, cx| {
|
self.lsp_store.update(cx, |lsp_store, cx| {
|
||||||
lsp_store.type_definitions(buffer, position, cx)
|
lsp_store.type_definitions(buffer, position, cx)
|
||||||
})
|
})
|
||||||
|
@ -3397,7 +3436,7 @@ impl Project {
|
||||||
position: T,
|
position: T,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Task<Result<Vec<LocationLink>>> {
|
) -> Task<Result<Vec<LocationLink>>> {
|
||||||
let position = position.to_point_utf16(buffer.read(cx));
|
let position = position.to_point_utf16(&buffer.read(cx).snapshot());
|
||||||
self.lsp_store.update(cx, |lsp_store, cx| {
|
self.lsp_store.update(cx, |lsp_store, cx| {
|
||||||
lsp_store.implementations(buffer, position, cx)
|
lsp_store.implementations(buffer, position, cx)
|
||||||
})
|
})
|
||||||
|
@ -3409,7 +3448,7 @@ impl Project {
|
||||||
position: T,
|
position: T,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Task<Result<Vec<Location>>> {
|
) -> Task<Result<Vec<Location>>> {
|
||||||
let position = position.to_point_utf16(buffer.read(cx));
|
let position = position.to_point_utf16(&buffer.read(cx).snapshot());
|
||||||
self.lsp_store.update(cx, |lsp_store, cx| {
|
self.lsp_store.update(cx, |lsp_store, cx| {
|
||||||
lsp_store.references(buffer, position, cx)
|
lsp_store.references(buffer, position, cx)
|
||||||
})
|
})
|
||||||
|
@ -3435,7 +3474,7 @@ impl Project {
|
||||||
position: T,
|
position: T,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Task<Result<Vec<DocumentHighlight>>> {
|
) -> Task<Result<Vec<DocumentHighlight>>> {
|
||||||
let position = position.to_point_utf16(buffer.read(cx));
|
let position = position.to_point_utf16(&buffer.read(cx).snapshot());
|
||||||
self.document_highlights_impl(buffer, position, cx)
|
self.document_highlights_impl(buffer, position, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3532,7 +3571,7 @@ impl Project {
|
||||||
position: T,
|
position: T,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Task<Vec<Hover>> {
|
) -> Task<Vec<Hover>> {
|
||||||
let position = position.to_point_utf16(buffer.read(cx));
|
let position = position.to_point_utf16(&buffer.read(cx).snapshot());
|
||||||
self.lsp_store
|
self.lsp_store
|
||||||
.update(cx, |lsp_store, cx| lsp_store.hover(buffer, position, cx))
|
.update(cx, |lsp_store, cx| lsp_store.hover(buffer, position, cx))
|
||||||
}
|
}
|
||||||
|
@ -3555,7 +3594,7 @@ impl Project {
|
||||||
context: CompletionContext,
|
context: CompletionContext,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Task<Result<Vec<CompletionResponse>>> {
|
) -> Task<Result<Vec<CompletionResponse>>> {
|
||||||
let position = position.to_point_utf16(buffer.read(cx));
|
let position = position.to_point_utf16(&buffer.read(cx).snapshot());
|
||||||
self.lsp_store.update(cx, |lsp_store, cx| {
|
self.lsp_store.update(cx, |lsp_store, cx| {
|
||||||
lsp_store.completions(buffer, position, context, cx)
|
lsp_store.completions(buffer, position, context, cx)
|
||||||
})
|
})
|
||||||
|
@ -3646,7 +3685,7 @@ impl Project {
|
||||||
position: T,
|
position: T,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Task<Result<PrepareRenameResponse>> {
|
) -> Task<Result<PrepareRenameResponse>> {
|
||||||
let position = position.to_point_utf16(buffer.read(cx));
|
let position = position.to_point_utf16(&buffer.read(cx).snapshot());
|
||||||
self.prepare_rename_impl(buffer, position, cx)
|
self.prepare_rename_impl(buffer, position, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3658,7 +3697,7 @@ impl Project {
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Task<Result<ProjectTransaction>> {
|
) -> Task<Result<ProjectTransaction>> {
|
||||||
let push_to_history = true;
|
let push_to_history = true;
|
||||||
let position = position.to_point_utf16(buffer.read(cx));
|
let position = position.to_point_utf16(&buffer.read(cx).snapshot());
|
||||||
self.request_lsp(
|
self.request_lsp(
|
||||||
buffer,
|
buffer,
|
||||||
LanguageServerToQuery::FirstCapable,
|
LanguageServerToQuery::FirstCapable,
|
||||||
|
@ -3725,8 +3764,10 @@ impl Project {
|
||||||
range: Range<T>,
|
range: Range<T>,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Task<anyhow::Result<Vec<InlayHint>>> {
|
) -> Task<anyhow::Result<Vec<InlayHint>>> {
|
||||||
|
let range = {
|
||||||
let buffer = buffer_handle.read(cx);
|
let buffer = buffer_handle.read(cx);
|
||||||
let range = buffer.anchor_before(range.start)..buffer.anchor_before(range.end);
|
buffer.anchor_before(range.start)..buffer.anchor_before(range.end)
|
||||||
|
};
|
||||||
self.lsp_store.update(cx, |lsp_store, cx| {
|
self.lsp_store.update(cx, |lsp_store, cx| {
|
||||||
lsp_store.inlay_hints(buffer_handle, range, cx)
|
lsp_store.inlay_hints(buffer_handle, range, cx)
|
||||||
})
|
})
|
||||||
|
@ -4213,8 +4254,8 @@ impl Project {
|
||||||
pub fn set_active_path(&mut self, entry: Option<ProjectPath>, cx: &mut Context<Self>) {
|
pub fn set_active_path(&mut self, entry: Option<ProjectPath>, cx: &mut Context<Self>) {
|
||||||
let new_active_entry = entry.and_then(|project_path| {
|
let new_active_entry = entry.and_then(|project_path| {
|
||||||
let worktree = self.worktree_for_id(project_path.worktree_id, cx)?;
|
let worktree = self.worktree_for_id(project_path.worktree_id, cx)?;
|
||||||
let entry = worktree.read(cx).entry_for_path(project_path.path)?;
|
let entry_id = worktree.read(cx).entry_for_path(project_path.path)?.id;
|
||||||
Some(entry.id)
|
Some(entry_id)
|
||||||
});
|
});
|
||||||
if new_active_entry != self.active_entry {
|
if new_active_entry != self.active_entry {
|
||||||
self.active_entry = new_active_entry;
|
self.active_entry = new_active_entry;
|
||||||
|
@ -4225,13 +4266,20 @@ impl Project {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pub fn language_servers_running_disk_based_diagnostics<'a>(
|
||||||
|
// &'a self,
|
||||||
|
// cx: &'a App,
|
||||||
|
// ) -> impl Iterator<Item = LanguageServerId> + 'a {
|
||||||
|
// self.lsp_store
|
||||||
|
// .read(cx)
|
||||||
|
// .language_servers_running_disk_based_diagnostics()
|
||||||
|
// }
|
||||||
pub fn language_servers_running_disk_based_diagnostics<'a>(
|
pub fn language_servers_running_disk_based_diagnostics<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
cx: &'a App,
|
cx: &'a App,
|
||||||
) -> impl Iterator<Item = LanguageServerId> + 'a {
|
) -> impl Iterator<Item = LanguageServerId> + 'a {
|
||||||
self.lsp_store
|
// todo!("language_servers_running_disk_based_diagnostics needs to be refactored to handle Ref type")
|
||||||
.read(cx)
|
std::iter::empty()
|
||||||
.language_servers_running_disk_based_diagnostics()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
|
pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
|
||||||
|
@ -4240,14 +4288,22 @@ impl Project {
|
||||||
.diagnostic_summary(include_ignored, cx)
|
.diagnostic_summary(include_ignored, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pub fn diagnostic_summaries<'a>(
|
||||||
|
// &'a self,
|
||||||
|
// include_ignored: bool,
|
||||||
|
// cx: &'a App,
|
||||||
|
// ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
|
||||||
|
// self.lsp_store
|
||||||
|
// .read(cx)
|
||||||
|
// .diagnostic_summaries(include_ignored, cx)
|
||||||
|
// }
|
||||||
pub fn diagnostic_summaries<'a>(
|
pub fn diagnostic_summaries<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
include_ignored: bool,
|
include_ignored: bool,
|
||||||
cx: &'a App,
|
cx: &'a App,
|
||||||
) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
|
) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
|
||||||
self.lsp_store
|
// todo!("diagnostic_summaries needs to be refactored to handle Ref type")
|
||||||
.read(cx)
|
std::iter::empty()
|
||||||
.diagnostic_summaries(include_ignored, cx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn active_entry(&self) -> Option<ProjectEntryId> {
|
pub fn active_entry(&self) -> Option<ProjectEntryId> {
|
||||||
|
@ -4306,25 +4362,26 @@ impl Project {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for worktree in worktree_store.visible_worktrees(cx) {
|
// TODO: Fix when visible_worktrees is refactored to handle Ref type
|
||||||
let worktree_root_name = worktree.read(cx).root_name();
|
// for worktree in worktree_store.visible_worktrees(cx) {
|
||||||
if let Ok(relative_path) = path.strip_prefix(worktree_root_name) {
|
// let worktree_root_name = worktree.read(cx).root_name();
|
||||||
return Some(ProjectPath {
|
// if let Ok(relative_path) = path.strip_prefix(worktree_root_name) {
|
||||||
worktree_id: worktree.read(cx).id(),
|
// return Some(ProjectPath {
|
||||||
path: relative_path.into(),
|
// worktree_id: worktree.read(cx).id(),
|
||||||
});
|
// path: relative_path.into(),
|
||||||
}
|
// });
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
for worktree in worktree_store.visible_worktrees(cx) {
|
// for worktree in worktree_store.visible_worktrees(cx) {
|
||||||
let worktree = worktree.read(cx);
|
// let worktree = worktree.read(cx);
|
||||||
if let Some(entry) = worktree.entry_for_path(path) {
|
// if let Some(entry) = worktree.entry_for_path(path) {
|
||||||
return Some(ProjectPath {
|
// return Some(ProjectPath {
|
||||||
worktree_id: worktree.id(),
|
// worktree_id: worktree.id(),
|
||||||
path: entry.path.clone(),
|
// path: entry.path.clone(),
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
|
@ -4867,16 +4924,21 @@ impl Project {
|
||||||
self.worktree_store.read(cx).worktree_metadata_protos(cx)
|
self.worktree_store.read(cx).worktree_metadata_protos(cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// /// Iterator of all open buffers that have unsaved changes
|
||||||
|
// pub fn dirty_buffers<'a>(&'a self, cx: &'a App) -> impl Iterator<Item = ProjectPath> + 'a {
|
||||||
|
// self.buffer_store.read(cx).buffers().filter_map(|buf| {
|
||||||
|
// let buf = buf.read(cx);
|
||||||
|
// if buf.is_dirty() {
|
||||||
|
// buf.project_path(cx)
|
||||||
|
// } else {
|
||||||
|
// None
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// }
|
||||||
/// Iterator of all open buffers that have unsaved changes
|
/// Iterator of all open buffers that have unsaved changes
|
||||||
pub fn dirty_buffers<'a>(&'a self, cx: &'a App) -> impl Iterator<Item = ProjectPath> + 'a {
|
pub fn dirty_buffers<'a>(&'a self, cx: &'a App) -> impl Iterator<Item = ProjectPath> + 'a {
|
||||||
self.buffer_store.read(cx).buffers().filter_map(|buf| {
|
// todo!("dirty_buffers needs to be refactored to handle Ref type")
|
||||||
let buf = buf.read(cx);
|
std::iter::empty()
|
||||||
if buf.is_dirty() {
|
|
||||||
buf.project_path(cx)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_worktrees_from_proto(
|
fn set_worktrees_from_proto(
|
||||||
|
@ -4908,11 +4970,18 @@ impl Project {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pub fn supplementary_language_servers<'a>(
|
||||||
|
// &'a self,
|
||||||
|
// cx: &'a App,
|
||||||
|
// ) -> impl 'a + Iterator<Item = (LanguageServerId, LanguageServerName)> {
|
||||||
|
// self.lsp_store.read(cx).supplementary_language_servers()
|
||||||
|
// }
|
||||||
pub fn supplementary_language_servers<'a>(
|
pub fn supplementary_language_servers<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
cx: &'a App,
|
cx: &'a App,
|
||||||
) -> impl 'a + Iterator<Item = (LanguageServerId, LanguageServerName)> {
|
) -> impl 'a + Iterator<Item = (LanguageServerId, LanguageServerName)> {
|
||||||
self.lsp_store.read(cx).supplementary_language_servers()
|
// todo!("supplementary_language_servers needs to be refactored to handle Ref type")
|
||||||
|
std::iter::empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn any_language_server_supports_inlay_hints(&self, buffer: &Buffer, cx: &mut App) -> bool {
|
pub fn any_language_server_supports_inlay_hints(&self, buffer: &Buffer, cx: &mut App) -> bool {
|
||||||
|
@ -5030,8 +5099,16 @@ impl Project {
|
||||||
self.git_store.read(cx).active_repository()
|
self.git_store.read(cx).active_repository()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn repositories<'a>(&self, cx: &'a App) -> &'a HashMap<RepositoryId, Entity<Repository>> {
|
// pub fn repositories<'a>(&self, cx: &'a App) -> &'a HashMap<RepositoryId, Entity<Repository>> {
|
||||||
self.git_store.read(cx).repositories()
|
// self.git_store.read(cx).repositories()
|
||||||
|
// }
|
||||||
|
pub fn repositories<'a>(&self, _cx: &'a App) -> &'a HashMap<RepositoryId, Entity<Repository>> {
|
||||||
|
// todo!("repositories needs to be refactored to handle Ref type")
|
||||||
|
// This can't return an empty iterator since it needs to return a reference
|
||||||
|
// For now, we'll leak a static empty HashMap
|
||||||
|
static EMPTY: std::sync::OnceLock<HashMap<RepositoryId, Entity<Repository>>> =
|
||||||
|
std::sync::OnceLock::new();
|
||||||
|
EMPTY.get_or_init(HashMap::default)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
|
pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
|
||||||
|
|
|
@ -117,7 +117,8 @@ async fn test_symlinks(cx: &mut gpui::TestAppContext) {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
project.update(cx, |project, cx| {
|
project.update(cx, |project, cx| {
|
||||||
let tree = project.worktrees(cx).next().unwrap().read(cx);
|
let worktree = project.worktrees(cx).next().unwrap();
|
||||||
|
let tree = worktree.read(cx);
|
||||||
assert_eq!(tree.file_count(), 5);
|
assert_eq!(tree.file_count(), 5);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
tree.inode_for_path("fennel/grape"),
|
tree.inode_for_path("fennel/grape"),
|
||||||
|
@ -1075,10 +1076,10 @@ async fn test_reporting_fs_changes_to_language_servers(cx: &mut gpui::TestAppCon
|
||||||
|
|
||||||
// Initially, we don't load ignored files because the language server has not explicitly asked us to watch them.
|
// Initially, we don't load ignored files because the language server has not explicitly asked us to watch them.
|
||||||
project.update(cx, |project, cx| {
|
project.update(cx, |project, cx| {
|
||||||
let worktree = project.worktrees(cx).next().unwrap();
|
let worktree_entity = project.worktrees(cx).next().unwrap();
|
||||||
|
let worktree = worktree_entity.read(cx);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
worktree
|
worktree
|
||||||
.read(cx)
|
|
||||||
.snapshot()
|
.snapshot()
|
||||||
.entries(true, 0)
|
.entries(true, 0)
|
||||||
.map(|entry| (entry.path.as_ref(), entry.is_ignored))
|
.map(|entry| (entry.path.as_ref(), entry.is_ignored))
|
||||||
|
@ -3014,7 +3015,10 @@ async fn test_definition(cx: &mut gpui::TestAppContext) {
|
||||||
.abs_path(cx),
|
.abs_path(cx),
|
||||||
Path::new(path!("/dir/a.rs")),
|
Path::new(path!("/dir/a.rs")),
|
||||||
);
|
);
|
||||||
assert_eq!(definition.target.range.to_offset(target_buffer), 9..10);
|
assert_eq!(
|
||||||
|
definition.target.range.to_offset(&target_buffer.snapshot()),
|
||||||
|
9..10
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
list_worktrees(&project, cx),
|
list_worktrees(&project, cx),
|
||||||
[
|
[
|
||||||
|
@ -3023,6 +3027,7 @@ async fn test_definition(cx: &mut gpui::TestAppContext) {
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
drop(target_buffer);
|
||||||
drop(definition);
|
drop(definition);
|
||||||
});
|
});
|
||||||
cx.update(|cx| {
|
cx.update(|cx| {
|
||||||
|
@ -3032,18 +3037,19 @@ async fn test_definition(cx: &mut gpui::TestAppContext) {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
fn list_worktrees<'a>(project: &'a Entity<Project>, cx: &'a App) -> Vec<(&'a Path, bool)> {
|
// fn list_worktrees<'a>(project: &'a Entity<Project>, cx: &'a App) -> Vec<(&'a Path, bool)> {
|
||||||
project
|
// project
|
||||||
.read(cx)
|
// .read(cx)
|
||||||
.worktrees(cx)
|
// .worktrees(cx)
|
||||||
.map(|worktree| {
|
// .map(|worktree| {
|
||||||
let worktree = worktree.read(cx);
|
// let worktree = worktree.read(cx);
|
||||||
(
|
// (
|
||||||
worktree.as_local().unwrap().abs_path().as_ref(),
|
// worktree.as_local().unwrap().abs_path().as_ref(),
|
||||||
worktree.is_visible(),
|
// worktree.is_visible(),
|
||||||
)
|
// )
|
||||||
})
|
// })
|
||||||
.collect::<Vec<_>>()
|
fn list_worktrees<'a>(_project: &'a Entity<Project>, _cx: &'a App) -> Vec<(&'a Path, bool)> {
|
||||||
|
todo!("list_worktrees needs to be refactored to handle Ref type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4823,8 +4829,8 @@ async fn test_lsp_rename_notifications(cx: &mut gpui::TestAppContext) {
|
||||||
let fake_server = fake_servers.next().await.unwrap();
|
let fake_server = fake_servers.next().await.unwrap();
|
||||||
let response = project.update(cx, |project, cx| {
|
let response = project.update(cx, |project, cx| {
|
||||||
let worktree = project.worktrees(cx).next().unwrap();
|
let worktree = project.worktrees(cx).next().unwrap();
|
||||||
let entry = worktree.read(cx).entry_for_path("one.rs").unwrap();
|
let entry_id = worktree.read(cx).entry_for_path("one.rs").unwrap().id;
|
||||||
project.rename_entry(entry.id, "three.rs".as_ref(), cx)
|
project.rename_entry(entry_id, "three.rs".as_ref(), cx)
|
||||||
});
|
});
|
||||||
let expected_edit = lsp::WorkspaceEdit {
|
let expected_edit = lsp::WorkspaceEdit {
|
||||||
changes: None,
|
changes: None,
|
||||||
|
@ -8162,8 +8168,8 @@ async fn test_update_gitignore(cx: &mut gpui::TestAppContext) {
|
||||||
|
|
||||||
// One file is unmodified, the other is ignored.
|
// One file is unmodified, the other is ignored.
|
||||||
cx.read(|cx| {
|
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), "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), "b.txt", None, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Change the gitignore, and stage the newly non-ignored file.
|
// Change the gitignore, and stage the newly non-ignored file.
|
||||||
|
@ -8181,10 +8187,10 @@ async fn test_update_gitignore(cx: &mut gpui::TestAppContext) {
|
||||||
|
|
||||||
cx.executor().run_until_parked();
|
cx.executor().run_until_parked();
|
||||||
cx.read(|cx| {
|
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(
|
assert_entry_git_state(
|
||||||
tree.read(cx),
|
&tree.read(cx),
|
||||||
repository.read(cx),
|
&repository.read(cx),
|
||||||
"b.txt",
|
"b.txt",
|
||||||
Some(StatusCode::Added),
|
Some(StatusCode::Added),
|
||||||
false,
|
false,
|
||||||
|
@ -8597,22 +8603,22 @@ async fn test_rescan_with_gitignore(cx: &mut gpui::TestAppContext) {
|
||||||
|
|
||||||
cx.read(|cx| {
|
cx.read(|cx| {
|
||||||
assert_entry_git_state(
|
assert_entry_git_state(
|
||||||
tree.read(cx),
|
&tree.read(cx),
|
||||||
repository.read(cx),
|
&repository.read(cx),
|
||||||
"tracked-dir/tracked-file1",
|
"tracked-dir/tracked-file1",
|
||||||
None,
|
None,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
assert_entry_git_state(
|
assert_entry_git_state(
|
||||||
tree.read(cx),
|
&tree.read(cx),
|
||||||
repository.read(cx),
|
&repository.read(cx),
|
||||||
"tracked-dir/ancestor-ignored-file1",
|
"tracked-dir/ancestor-ignored-file1",
|
||||||
None,
|
None,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
assert_entry_git_state(
|
assert_entry_git_state(
|
||||||
tree.read(cx),
|
&tree.read(cx),
|
||||||
repository.read(cx),
|
&repository.read(cx),
|
||||||
"ignored-dir/ignored-file1",
|
"ignored-dir/ignored-file1",
|
||||||
None,
|
None,
|
||||||
true,
|
true,
|
||||||
|
@ -8649,22 +8655,22 @@ async fn test_rescan_with_gitignore(cx: &mut gpui::TestAppContext) {
|
||||||
cx.executor().run_until_parked();
|
cx.executor().run_until_parked();
|
||||||
cx.read(|cx| {
|
cx.read(|cx| {
|
||||||
assert_entry_git_state(
|
assert_entry_git_state(
|
||||||
tree.read(cx),
|
&tree.read(cx),
|
||||||
repository.read(cx),
|
&repository.read(cx),
|
||||||
"tracked-dir/tracked-file2",
|
"tracked-dir/tracked-file2",
|
||||||
Some(StatusCode::Added),
|
Some(StatusCode::Added),
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
assert_entry_git_state(
|
assert_entry_git_state(
|
||||||
tree.read(cx),
|
&tree.read(cx),
|
||||||
repository.read(cx),
|
&repository.read(cx),
|
||||||
"tracked-dir/ancestor-ignored-file2",
|
"tracked-dir/ancestor-ignored-file2",
|
||||||
None,
|
None,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
assert_entry_git_state(
|
assert_entry_git_state(
|
||||||
tree.read(cx),
|
&tree.read(cx),
|
||||||
repository.read(cx),
|
&repository.read(cx),
|
||||||
"ignored-dir/ignored-file2",
|
"ignored-dir/ignored-file2",
|
||||||
None,
|
None,
|
||||||
true,
|
true,
|
||||||
|
|
|
@ -305,12 +305,14 @@ impl Inventory {
|
||||||
let last_scheduled_scenarios = self.last_scheduled_scenarios.iter().cloned().collect();
|
let last_scheduled_scenarios = self.last_scheduled_scenarios.iter().cloned().collect();
|
||||||
|
|
||||||
let adapter = task_contexts.location().and_then(|location| {
|
let adapter = task_contexts.location().and_then(|location| {
|
||||||
let (file, language) = {
|
let (file, language_name, language) = {
|
||||||
let buffer = location.buffer.read(cx);
|
let buffer = location.buffer.read(cx);
|
||||||
(buffer.file(), buffer.language())
|
let file = buffer.file().cloned();
|
||||||
};
|
let language = buffer.language().clone();
|
||||||
let language_name = language.as_ref().map(|l| l.name());
|
let language_name = language.as_ref().map(|l| l.name());
|
||||||
let adapter = language_settings(language_name, file, cx)
|
(file, language_name, language)
|
||||||
|
};
|
||||||
|
let adapter = language_settings(language_name, file.as_ref(), cx)
|
||||||
.debuggers
|
.debuggers
|
||||||
.first()
|
.first()
|
||||||
.map(SharedString::from)
|
.map(SharedString::from)
|
||||||
|
@ -435,11 +437,17 @@ impl Inventory {
|
||||||
let fs = self.fs.clone();
|
let fs = self.fs.clone();
|
||||||
let worktree = task_contexts.worktree();
|
let worktree = task_contexts.worktree();
|
||||||
let location = task_contexts.location();
|
let location = task_contexts.location();
|
||||||
let language = location.and_then(|location| location.buffer.read(cx).language());
|
let language = location.and_then(|location| {
|
||||||
|
let buffer = location.buffer.read(cx);
|
||||||
|
buffer.language().clone()
|
||||||
|
});
|
||||||
let task_source_kind = language.as_ref().map(|language| TaskSourceKind::Language {
|
let task_source_kind = language.as_ref().map(|language| TaskSourceKind::Language {
|
||||||
name: language.name().into(),
|
name: language.name().into(),
|
||||||
});
|
});
|
||||||
let file = location.and_then(|location| location.buffer.read(cx).file().cloned());
|
let file = location.and_then(|location| {
|
||||||
|
let buffer = location.buffer.read(cx);
|
||||||
|
buffer.file().cloned()
|
||||||
|
});
|
||||||
|
|
||||||
let mut task_labels_to_ids = HashMap::<String, HashSet<TaskId>>::default();
|
let mut task_labels_to_ids = HashMap::<String, HashSet<TaskId>>::default();
|
||||||
let mut lru_score = 0_u32;
|
let mut lru_score = 0_u32;
|
||||||
|
|
|
@ -478,9 +478,12 @@ impl Project {
|
||||||
let bin_path = venv_path.join(bin_dir_name);
|
let bin_path = venv_path.join(bin_dir_name);
|
||||||
self.find_worktree(&bin_path, cx)
|
self.find_worktree(&bin_path, cx)
|
||||||
.and_then(|(worktree, relative_path)| {
|
.and_then(|(worktree, relative_path)| {
|
||||||
worktree.read(cx).entry_for_path(&relative_path)
|
worktree
|
||||||
|
.read(cx)
|
||||||
|
.entry_for_path(&relative_path)
|
||||||
|
.map(|entry| entry.is_dir())
|
||||||
})
|
})
|
||||||
.is_some_and(|entry| entry.is_dir())
|
.unwrap_or(false)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -491,7 +494,7 @@ impl Project {
|
||||||
cx: &App,
|
cx: &App,
|
||||||
) -> Option<PathBuf> {
|
) -> Option<PathBuf> {
|
||||||
let (worktree, _) = self.find_worktree(abs_path, cx)?;
|
let (worktree, _) = self.find_worktree(abs_path, cx)?;
|
||||||
let fs = worktree.read(cx).as_local()?.fs();
|
let fs = worktree.read(cx).as_local()?.fs().clone();
|
||||||
let bin_dir_name = match std::env::consts::OS {
|
let bin_dir_name = match std::env::consts::OS {
|
||||||
"windows" => "Scripts",
|
"windows" => "Scripts",
|
||||||
_ => "bin",
|
_ => "bin",
|
||||||
|
|
|
@ -338,15 +338,16 @@ impl LocalToolchainStore {
|
||||||
.ok()?;
|
.ok()?;
|
||||||
let toolchains = language.toolchain_lister()?;
|
let toolchains = language.toolchain_lister()?;
|
||||||
let manifest_name = toolchains.manifest_name();
|
let manifest_name = toolchains.manifest_name();
|
||||||
let (snapshot, worktree) = this
|
let worktree = this
|
||||||
.update(cx, |this, cx| {
|
.update(cx, |this, cx| {
|
||||||
this.worktree_store
|
let store = this.worktree_store.read(cx);
|
||||||
.read(cx)
|
store.worktree_for_id(path.worktree_id, cx)
|
||||||
.worktree_for_id(path.worktree_id, cx)
|
|
||||||
.map(|worktree| (worktree.read(cx).snapshot(), worktree))
|
|
||||||
})
|
})
|
||||||
.ok()
|
.ok()
|
||||||
.flatten()?;
|
.flatten()?;
|
||||||
|
let snapshot = worktree
|
||||||
|
.read_with(cx, |worktree, _| worktree.snapshot())
|
||||||
|
.ok()?;
|
||||||
let worktree_id = snapshot.id();
|
let worktree_id = snapshot.id();
|
||||||
let worktree_root = snapshot.abs_path().to_path_buf();
|
let worktree_root = snapshot.abs_path().to_path_buf();
|
||||||
let relative_path = manifest_tree
|
let relative_path = manifest_tree
|
||||||
|
|
|
@ -185,22 +185,36 @@ impl WorktreeStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn entry_for_id<'a>(&'a self, entry_id: ProjectEntryId, cx: &'a App) -> Option<&'a Entry> {
|
// pub fn entry_for_id<'a>(&'a self, entry_id: ProjectEntryId, cx: &'a App) -> Option<&'a Entry> {
|
||||||
self.worktrees()
|
// self.worktrees()
|
||||||
.find_map(|worktree| worktree.read(cx).entry_for_id(entry_id))
|
// .find_map(|worktree| worktree.read(cx).entry_for_id(entry_id))
|
||||||
|
// }
|
||||||
|
pub fn entry_for_id<'a>(
|
||||||
|
&'a self,
|
||||||
|
_entry_id: ProjectEntryId,
|
||||||
|
_cx: &'a App,
|
||||||
|
) -> Option<&'a Entry> {
|
||||||
|
todo!("entry_for_id needs to be refactored to handle Ref type")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pub fn worktree_and_entry_for_id<'a>(
|
||||||
|
// &'a self,
|
||||||
|
// entry_id: ProjectEntryId,
|
||||||
|
// cx: &'a App,
|
||||||
|
// ) -> Option<(Entity<Worktree>, &'a Entry)> {
|
||||||
|
// self.worktrees().find_map(|worktree| {
|
||||||
|
// worktree
|
||||||
|
// .read(cx)
|
||||||
|
// .entry_for_id(entry_id)
|
||||||
|
// .map(|e| (worktree.clone(), e))
|
||||||
|
// })
|
||||||
|
// }
|
||||||
pub fn worktree_and_entry_for_id<'a>(
|
pub fn worktree_and_entry_for_id<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
entry_id: ProjectEntryId,
|
_entry_id: ProjectEntryId,
|
||||||
cx: &'a App,
|
_cx: &'a App,
|
||||||
) -> Option<(Entity<Worktree>, &'a Entry)> {
|
) -> Option<(Entity<Worktree>, &'a Entry)> {
|
||||||
self.worktrees().find_map(|worktree| {
|
todo!("worktree_and_entry_for_id needs to be refactored to handle Ref type")
|
||||||
worktree
|
|
||||||
.read(cx)
|
|
||||||
.entry_for_id(entry_id)
|
|
||||||
.map(|e| (worktree.clone(), e))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn entry_for_path(&self, path: &ProjectPath, cx: &App) -> Option<Entry> {
|
pub fn entry_for_path(&self, path: &ProjectPath, cx: &App) -> Option<Entry> {
|
||||||
|
@ -453,7 +467,8 @@ impl WorktreeStore {
|
||||||
.drain(..)
|
.drain(..)
|
||||||
.filter_map(|worktree| {
|
.filter_map(|worktree| {
|
||||||
let worktree = worktree.upgrade()?;
|
let worktree = worktree.upgrade()?;
|
||||||
Some((worktree.read(cx).id(), worktree))
|
let worktree_id = worktree.read(cx).id();
|
||||||
|
Some((worktree_id, worktree))
|
||||||
})
|
})
|
||||||
.collect::<HashMap<_, _>>();
|
.collect::<HashMap<_, _>>();
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,10 @@ pub struct ProtoMessageHandlerSet {
|
||||||
pub message_handlers: HashMap<TypeId, ProtoMessageHandler>,
|
pub message_handlers: HashMap<TypeId, ProtoMessageHandler>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo! try to remove these. we can't store handles inside send/sync stuff
|
||||||
|
unsafe impl Send for ProtoMessageHandlerSet {}
|
||||||
|
unsafe impl Sync for ProtoMessageHandlerSet {}
|
||||||
|
|
||||||
pub type ProtoMessageHandler = Arc<
|
pub type ProtoMessageHandler = Arc<
|
||||||
dyn Send
|
dyn Send
|
||||||
+ Sync
|
+ Sync
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use gpui::{App, AppContext as _, Context, Entity, Global, SharedString, Task};
|
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;
|
use zed_llm_client::WebSearchResponse;
|
||||||
|
|
||||||
pub fn init(cx: &mut App) {
|
pub fn init(cx: &mut App) {
|
||||||
|
@ -32,7 +32,7 @@ impl WebSearchRegistry {
|
||||||
cx.global::<GlobalWebSearchRegistry>().0.clone()
|
cx.global::<GlobalWebSearchRegistry>().0.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_global(cx: &App) -> &Self {
|
pub fn read_global(cx: &App) -> Ref<Self> {
|
||||||
cx.global::<GlobalWebSearchRegistry>().0.read(cx)
|
cx.global::<GlobalWebSearchRegistry>().0.read(cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ use std::{
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
collections::hash_map,
|
collections::hash_map,
|
||||||
convert::TryFrom,
|
convert::TryFrom,
|
||||||
ffi::OsStr,
|
ffi::{OsStr, OsString},
|
||||||
fmt,
|
fmt,
|
||||||
future::Future,
|
future::Future,
|
||||||
mem::{self},
|
mem::{self},
|
||||||
|
@ -2667,17 +2667,18 @@ impl Snapshot {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn entry_for_path(&self, path: impl AsRef<Path>) -> Option<&Entry> {
|
pub fn entry_for_path(&self, path: impl AsRef<Path>) -> Option<&Entry> {
|
||||||
let path = path.as_ref();
|
// let path = path.as_ref();
|
||||||
debug_assert!(path.is_relative());
|
// debug_assert!(path.is_relative());
|
||||||
self.traverse_from_path(true, true, true, path)
|
// self.traverse_from_path(true, true, true, path)
|
||||||
.entry()
|
// .entry()
|
||||||
.and_then(|entry| {
|
// .and_then(|entry| {
|
||||||
if entry.path.as_ref() == path {
|
// if entry.path.as_ref() == path {
|
||||||
Some(entry)
|
// Some(entry)
|
||||||
} else {
|
// } else {
|
||||||
None
|
// None
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn entry_for_id(&self, id: ProjectEntryId) -> Option<&Entry> {
|
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
|
/// 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.
|
/// 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
|
self.path
|
||||||
.file_name()
|
.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 {
|
fn worktree_id(&self, cx: &App) -> WorktreeId {
|
||||||
|
@ -3357,14 +3359,16 @@ impl language::LocalFile for File {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load(&self, cx: &App) -> Task<Result<String>> {
|
fn load(&self, cx: &App) -> Task<Result<String>> {
|
||||||
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 abs_path = worktree.absolutize(&self.path);
|
||||||
let fs = worktree.fs.clone();
|
let fs = worktree.fs.clone();
|
||||||
cx.background_spawn(async move { fs.load(&abs_path?).await })
|
cx.background_spawn(async move { fs.load(&abs_path?).await })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_bytes(&self, cx: &App) -> Task<Result<Vec<u8>>> {
|
fn load_bytes(&self, cx: &App) -> Task<Result<Vec<u8>>> {
|
||||||
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 abs_path = worktree.absolutize(&self.path);
|
||||||
let fs = worktree.fs.clone();
|
let fs = worktree.fs.clone();
|
||||||
cx.background_spawn(async move { fs.load_bytes(&abs_path?).await })
|
cx.background_spawn(async move { fs.load_bytes(&abs_path?).await })
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue