Rename Handle to Model

This commit is contained in:
Antonio Scandurra 2023-10-30 19:44:01 +01:00
parent 14d24a9ac6
commit 1a54ac0d69
32 changed files with 11195 additions and 482 deletions

View file

@ -12,7 +12,7 @@ use client2::{
use collections::HashSet;
use futures::{future::Shared, FutureExt};
use gpui2::{
AppContext, AsyncAppContext, Context, EventEmitter, Handle, ModelContext, Subscription, Task,
AppContext, AsyncAppContext, Context, EventEmitter, Model, ModelContext, Subscription, Task,
WeakHandle,
};
use postage::watch;
@ -23,10 +23,10 @@ use std::sync::Arc;
pub use participant::ParticipantLocation;
pub use room::Room;
pub fn init(client: Arc<Client>, user_store: Handle<UserStore>, cx: &mut AppContext) {
pub fn init(client: Arc<Client>, user_store: Model<UserStore>, cx: &mut AppContext) {
CallSettings::register(cx);
let active_call = cx.entity(|cx| ActiveCall::new(client, user_store, cx));
let active_call = cx.build_model(|cx| ActiveCall::new(client, user_store, cx));
cx.set_global(active_call);
}
@ -40,8 +40,8 @@ pub struct IncomingCall {
/// Singleton global maintaining the user's participation in a room across workspaces.
pub struct ActiveCall {
room: Option<(Handle<Room>, Vec<Subscription>)>,
pending_room_creation: Option<Shared<Task<Result<Handle<Room>, Arc<anyhow::Error>>>>>,
room: Option<(Model<Room>, Vec<Subscription>)>,
pending_room_creation: Option<Shared<Task<Result<Model<Room>, Arc<anyhow::Error>>>>>,
location: Option<WeakHandle<Project>>,
pending_invites: HashSet<u64>,
incoming_call: (
@ -49,7 +49,7 @@ pub struct ActiveCall {
watch::Receiver<Option<IncomingCall>>,
),
client: Arc<Client>,
user_store: Handle<UserStore>,
user_store: Model<UserStore>,
_subscriptions: Vec<client2::Subscription>,
}
@ -58,11 +58,7 @@ impl EventEmitter for ActiveCall {
}
impl ActiveCall {
fn new(
client: Arc<Client>,
user_store: Handle<UserStore>,
cx: &mut ModelContext<Self>,
) -> Self {
fn new(client: Arc<Client>, user_store: Model<UserStore>, cx: &mut ModelContext<Self>) -> Self {
Self {
room: None,
pending_room_creation: None,
@ -84,7 +80,7 @@ impl ActiveCall {
}
async fn handle_incoming_call(
this: Handle<Self>,
this: Model<Self>,
envelope: TypedEnvelope<proto::IncomingCall>,
_: Arc<Client>,
mut cx: AsyncAppContext,
@ -112,7 +108,7 @@ impl ActiveCall {
}
async fn handle_call_canceled(
this: Handle<Self>,
this: Model<Self>,
envelope: TypedEnvelope<proto::CallCanceled>,
_: Arc<Client>,
mut cx: AsyncAppContext,
@ -129,14 +125,14 @@ impl ActiveCall {
Ok(())
}
pub fn global(cx: &AppContext) -> Handle<Self> {
cx.global::<Handle<Self>>().clone()
pub fn global(cx: &AppContext) -> Model<Self> {
cx.global::<Model<Self>>().clone()
}
pub fn invite(
&mut self,
called_user_id: u64,
initial_project: Option<Handle<Project>>,
initial_project: Option<Model<Project>>,
cx: &mut ModelContext<Self>,
) -> Task<Result<()>> {
if !self.pending_invites.insert(called_user_id) {
@ -291,7 +287,7 @@ impl ActiveCall {
&mut self,
channel_id: u64,
cx: &mut ModelContext<Self>,
) -> Task<Result<Handle<Room>>> {
) -> Task<Result<Model<Room>>> {
if let Some(room) = self.room().cloned() {
if room.read(cx).channel_id() == Some(channel_id) {
return Task::ready(Ok(room));
@ -327,7 +323,7 @@ impl ActiveCall {
pub fn share_project(
&mut self,
project: Handle<Project>,
project: Model<Project>,
cx: &mut ModelContext<Self>,
) -> Task<Result<u64>> {
if let Some((room, _)) = self.room.as_ref() {
@ -340,7 +336,7 @@ impl ActiveCall {
pub fn unshare_project(
&mut self,
project: Handle<Project>,
project: Model<Project>,
cx: &mut ModelContext<Self>,
) -> Result<()> {
if let Some((room, _)) = self.room.as_ref() {
@ -357,7 +353,7 @@ impl ActiveCall {
pub fn set_location(
&mut self,
project: Option<&Handle<Project>>,
project: Option<&Model<Project>>,
cx: &mut ModelContext<Self>,
) -> Task<Result<()>> {
if project.is_some() || !*ZED_ALWAYS_ACTIVE {
@ -371,7 +367,7 @@ impl ActiveCall {
fn set_room(
&mut self,
room: Option<Handle<Room>>,
room: Option<Model<Room>>,
cx: &mut ModelContext<Self>,
) -> Task<Result<()>> {
if room.as_ref() != self.room.as_ref().map(|room| &room.0) {
@ -407,7 +403,7 @@ impl ActiveCall {
}
}
pub fn room(&self) -> Option<&Handle<Room>> {
pub fn room(&self) -> Option<&Model<Room>> {
self.room.as_ref().map(|(room, _)| room)
}

View file

@ -16,7 +16,7 @@ use collections::{BTreeMap, HashMap, HashSet};
use fs::Fs;
use futures::{FutureExt, StreamExt};
use gpui2::{
AppContext, AsyncAppContext, Context, EventEmitter, Handle, ModelContext, Task, WeakHandle,
AppContext, AsyncAppContext, Context, EventEmitter, Model, ModelContext, Task, WeakHandle,
};
use language2::LanguageRegistry;
use live_kit_client::{LocalTrackPublication, RemoteAudioTrackUpdate, RemoteVideoTrackUpdate};
@ -70,7 +70,7 @@ pub struct Room {
pending_call_count: usize,
leave_when_empty: bool,
client: Arc<Client>,
user_store: Handle<UserStore>,
user_store: Model<UserStore>,
follows_by_leader_id_project_id: HashMap<(PeerId, u64), Vec<PeerId>>,
client_subscriptions: Vec<client2::Subscription>,
_subscriptions: Vec<gpui2::Subscription>,
@ -111,7 +111,7 @@ impl Room {
channel_id: Option<u64>,
live_kit_connection_info: Option<proto::LiveKitConnectionInfo>,
client: Arc<Client>,
user_store: Handle<UserStore>,
user_store: Model<UserStore>,
cx: &mut ModelContext<Self>,
) -> Self {
todo!()
@ -237,15 +237,15 @@ impl Room {
pub(crate) fn create(
called_user_id: u64,
initial_project: Option<Handle<Project>>,
initial_project: Option<Model<Project>>,
client: Arc<Client>,
user_store: Handle<UserStore>,
user_store: Model<UserStore>,
cx: &mut AppContext,
) -> Task<Result<Handle<Self>>> {
) -> Task<Result<Model<Self>>> {
cx.spawn(move |mut cx| async move {
let response = client.request(proto::CreateRoom {}).await?;
let room_proto = response.room.ok_or_else(|| anyhow!("invalid room"))?;
let room = cx.entity(|cx| {
let room = cx.build_model(|cx| {
Self::new(
room_proto.id,
None,
@ -283,9 +283,9 @@ impl Room {
pub(crate) fn join_channel(
channel_id: u64,
client: Arc<Client>,
user_store: Handle<UserStore>,
user_store: Model<UserStore>,
cx: &mut AppContext,
) -> Task<Result<Handle<Self>>> {
) -> Task<Result<Model<Self>>> {
cx.spawn(move |cx| async move {
Self::from_join_response(
client.request(proto::JoinChannel { channel_id }).await?,
@ -299,9 +299,9 @@ impl Room {
pub(crate) fn join(
call: &IncomingCall,
client: Arc<Client>,
user_store: Handle<UserStore>,
user_store: Model<UserStore>,
cx: &mut AppContext,
) -> Task<Result<Handle<Self>>> {
) -> Task<Result<Model<Self>>> {
let id = call.room_id;
cx.spawn(move |cx| async move {
Self::from_join_response(
@ -343,11 +343,11 @@ impl Room {
fn from_join_response(
response: proto::JoinRoomResponse,
client: Arc<Client>,
user_store: Handle<UserStore>,
user_store: Model<UserStore>,
mut cx: AsyncAppContext,
) -> Result<Handle<Self>> {
) -> Result<Model<Self>> {
let room_proto = response.room.ok_or_else(|| anyhow!("invalid room"))?;
let room = cx.entity(|cx| {
let room = cx.build_model(|cx| {
Self::new(
room_proto.id,
response.channel_id,
@ -661,7 +661,7 @@ impl Room {
}
async fn handle_room_updated(
this: Handle<Self>,
this: Model<Self>,
envelope: TypedEnvelope<proto::RoomUpdated>,
_: Arc<Client>,
mut cx: AsyncAppContext,
@ -1101,7 +1101,7 @@ impl Room {
language_registry: Arc<LanguageRegistry>,
fs: Arc<dyn Fs>,
cx: &mut ModelContext<Self>,
) -> Task<Result<Handle<Project>>> {
) -> Task<Result<Model<Project>>> {
let client = self.client.clone();
let user_store = self.user_store.clone();
cx.emit(Event::RemoteProjectJoined { project_id: id });
@ -1125,7 +1125,7 @@ impl Room {
pub(crate) fn share_project(
&mut self,
project: Handle<Project>,
project: Model<Project>,
cx: &mut ModelContext<Self>,
) -> Task<Result<u64>> {
if let Some(project_id) = project.read(cx).remote_id() {
@ -1161,7 +1161,7 @@ impl Room {
pub(crate) fn unshare_project(
&mut self,
project: Handle<Project>,
project: Model<Project>,
cx: &mut ModelContext<Self>,
) -> Result<()> {
let project_id = match project.read(cx).remote_id() {
@ -1175,7 +1175,7 @@ impl Room {
pub(crate) fn set_location(
&mut self,
project: Option<&Handle<Project>>,
project: Option<&Model<Project>>,
cx: &mut ModelContext<Self>,
) -> Task<Result<()>> {
if self.status.is_offline() {

View file

@ -14,7 +14,7 @@ use futures::{
future::BoxFuture, AsyncReadExt, FutureExt, SinkExt, StreamExt, TryFutureExt as _, TryStreamExt,
};
use gpui2::{
serde_json, AnyHandle, AnyWeakHandle, AppContext, AsyncAppContext, Handle, SemanticVersion,
serde_json, AnyHandle, AnyWeakHandle, AppContext, AsyncAppContext, Model, SemanticVersion,
Task, WeakHandle,
};
use lazy_static::lazy_static;
@ -314,7 +314,7 @@ impl<T> PendingEntitySubscription<T>
where
T: 'static + Send,
{
pub fn set_model(mut self, model: &Handle<T>, cx: &mut AsyncAppContext) -> Subscription {
pub fn set_model(mut self, model: &Model<T>, cx: &mut AsyncAppContext) -> Subscription {
self.consumed = true;
let mut state = self.client.state.write();
let id = (TypeId::of::<T>(), self.remote_id);
@ -558,7 +558,7 @@ impl Client {
where
M: EnvelopedMessage,
E: 'static + Send,
H: 'static + Send + Sync + Fn(Handle<E>, TypedEnvelope<M>, Arc<Self>, AsyncAppContext) -> F,
H: 'static + Send + Sync + Fn(Model<E>, TypedEnvelope<M>, Arc<Self>, AsyncAppContext) -> F,
F: 'static + Future<Output = Result<()>> + Send,
{
let message_type_id = TypeId::of::<M>();
@ -600,7 +600,7 @@ impl Client {
where
M: RequestMessage,
E: 'static + Send,
H: 'static + Send + Sync + Fn(Handle<E>, TypedEnvelope<M>, Arc<Self>, AsyncAppContext) -> F,
H: 'static + Send + Sync + Fn(Model<E>, TypedEnvelope<M>, Arc<Self>, AsyncAppContext) -> F,
F: 'static + Future<Output = Result<M::Response>> + Send,
{
self.add_message_handler(model, move |handle, envelope, this, cx| {
@ -616,7 +616,7 @@ impl Client {
where
M: EntityMessage,
E: 'static + Send,
H: 'static + Send + Sync + Fn(Handle<E>, TypedEnvelope<M>, Arc<Self>, AsyncAppContext) -> F,
H: 'static + Send + Sync + Fn(Model<E>, TypedEnvelope<M>, Arc<Self>, AsyncAppContext) -> F,
F: 'static + Future<Output = Result<()>> + Send,
{
self.add_entity_message_handler::<M, E, _, _>(move |subscriber, message, client, cx| {
@ -667,7 +667,7 @@ impl Client {
where
M: EntityMessage + RequestMessage,
E: 'static + Send,
H: 'static + Send + Sync + Fn(Handle<E>, TypedEnvelope<M>, Arc<Self>, AsyncAppContext) -> F,
H: 'static + Send + Sync + Fn(Model<E>, TypedEnvelope<M>, Arc<Self>, AsyncAppContext) -> F,
F: 'static + Future<Output = Result<M::Response>> + Send,
{
self.add_model_message_handler(move |entity, envelope, client, cx| {
@ -1546,7 +1546,7 @@ mod tests {
let (done_tx1, mut done_rx1) = smol::channel::unbounded();
let (done_tx2, mut done_rx2) = smol::channel::unbounded();
client.add_model_message_handler(
move |model: Handle<Model>, _: TypedEnvelope<proto::JoinProject>, _, mut cx| {
move |model: Model<TestModel>, _: TypedEnvelope<proto::JoinProject>, _, mut cx| {
match model.update(&mut cx, |model, _| model.id).unwrap() {
1 => done_tx1.try_send(()).unwrap(),
2 => done_tx2.try_send(()).unwrap(),
@ -1555,15 +1555,15 @@ mod tests {
async { Ok(()) }
},
);
let model1 = cx.entity(|_| Model {
let model1 = cx.build_model(|_| TestModel {
id: 1,
subscription: None,
});
let model2 = cx.entity(|_| Model {
let model2 = cx.build_model(|_| TestModel {
id: 2,
subscription: None,
});
let model3 = cx.entity(|_| Model {
let model3 = cx.build_model(|_| TestModel {
id: 3,
subscription: None,
});
@ -1596,7 +1596,7 @@ mod tests {
let client = cx.update(|cx| Client::new(FakeHttpClient::with_404_response(), cx));
let server = FakeServer::for_client(user_id, &client, cx).await;
let model = cx.entity(|_| Model::default());
let model = cx.build_model(|_| TestModel::default());
let (done_tx1, _done_rx1) = smol::channel::unbounded();
let (done_tx2, mut done_rx2) = smol::channel::unbounded();
let subscription1 = client.add_message_handler(
@ -1624,11 +1624,11 @@ mod tests {
let client = cx.update(|cx| Client::new(FakeHttpClient::with_404_response(), cx));
let server = FakeServer::for_client(user_id, &client, cx).await;
let model = cx.entity(|_| Model::default());
let model = cx.build_model(|_| TestModel::default());
let (done_tx, mut done_rx) = smol::channel::unbounded();
let subscription = client.add_message_handler(
model.clone().downgrade(),
move |model: Handle<Model>, _: TypedEnvelope<proto::Ping>, _, mut cx| {
move |model: Model<TestModel>, _: TypedEnvelope<proto::Ping>, _, mut cx| {
model
.update(&mut cx, |model, _| model.subscription.take())
.unwrap();
@ -1644,7 +1644,7 @@ mod tests {
}
#[derive(Default)]
struct Model {
struct TestModel {
id: usize,
subscription: Option<Subscription>,
}

View file

@ -1,7 +1,7 @@
use crate::{Client, Connection, Credentials, EstablishConnectionError, UserStore};
use anyhow::{anyhow, Result};
use futures::{stream::BoxStream, StreamExt};
use gpui2::{Context, Executor, Handle, TestAppContext};
use gpui2::{Context, Executor, Model, TestAppContext};
use parking_lot::Mutex;
use rpc2::{
proto::{self, GetPrivateUserInfo, GetPrivateUserInfoResponse},
@ -194,9 +194,9 @@ impl FakeServer {
&self,
client: Arc<Client>,
cx: &mut TestAppContext,
) -> Handle<UserStore> {
) -> Model<UserStore> {
let http_client = FakeHttpClient::with_404_response();
let user_store = cx.entity(|cx| UserStore::new(client, http_client, cx));
let user_store = cx.build_model(|cx| UserStore::new(client, http_client, cx));
assert_eq!(
self.receive::<proto::GetUsers>()
.await

View file

@ -3,7 +3,7 @@ use anyhow::{anyhow, Context, Result};
use collections::{hash_map::Entry, HashMap, HashSet};
use feature_flags2::FeatureFlagAppExt;
use futures::{channel::mpsc, future, AsyncReadExt, Future, StreamExt};
use gpui2::{AsyncAppContext, EventEmitter, Handle, ImageData, ModelContext, Task};
use gpui2::{AsyncAppContext, EventEmitter, ImageData, Model, ModelContext, Task};
use postage::{sink::Sink, watch};
use rpc2::proto::{RequestMessage, UsersResponse};
use std::sync::{Arc, Weak};
@ -213,7 +213,7 @@ impl UserStore {
}
async fn handle_update_invite_info(
this: Handle<Self>,
this: Model<Self>,
message: TypedEnvelope<proto::UpdateInviteInfo>,
_: Arc<Client>,
mut cx: AsyncAppContext,
@ -229,7 +229,7 @@ impl UserStore {
}
async fn handle_show_contacts(
this: Handle<Self>,
this: Model<Self>,
_: TypedEnvelope<proto::ShowContacts>,
_: Arc<Client>,
mut cx: AsyncAppContext,
@ -243,7 +243,7 @@ impl UserStore {
}
async fn handle_update_contacts(
this: Handle<Self>,
this: Model<Self>,
message: TypedEnvelope<proto::UpdateContacts>,
_: Arc<Client>,
mut cx: AsyncAppContext,
@ -690,7 +690,7 @@ impl User {
impl Contact {
async fn from_proto(
contact: proto::Contact,
user_store: &Handle<UserStore>,
user_store: &Model<UserStore>,
cx: &mut AsyncAppContext,
) -> Result<Self> {
let user = user_store

View file

@ -7,7 +7,7 @@ use async_tar::Archive;
use collections::{HashMap, HashSet};
use futures::{channel::oneshot, future::Shared, Future, FutureExt, TryFutureExt};
use gpui2::{
AppContext, AsyncAppContext, Context, EntityId, EventEmitter, Handle, ModelContext, Task,
AppContext, AsyncAppContext, Context, EntityId, EventEmitter, Model, ModelContext, Task,
WeakHandle,
};
use language2::{
@ -49,7 +49,7 @@ pub fn init(
node_runtime: Arc<dyn NodeRuntime>,
cx: &mut AppContext,
) {
let copilot = cx.entity({
let copilot = cx.build_model({
let node_runtime = node_runtime.clone();
move |cx| Copilot::start(new_server_id, http, node_runtime, cx)
});
@ -183,7 +183,7 @@ struct RegisteredBuffer {
impl RegisteredBuffer {
fn report_changes(
&mut self,
buffer: &Handle<Buffer>,
buffer: &Model<Buffer>,
cx: &mut ModelContext<Copilot>,
) -> oneshot::Receiver<(i32, BufferSnapshot)> {
let (done_tx, done_rx) = oneshot::channel();
@ -292,9 +292,9 @@ impl EventEmitter for Copilot {
}
impl Copilot {
pub fn global(cx: &AppContext) -> Option<Handle<Self>> {
if cx.has_global::<Handle<Self>>() {
Some(cx.global::<Handle<Self>>().clone())
pub fn global(cx: &AppContext) -> Option<Model<Self>> {
if cx.has_global::<Model<Self>>() {
Some(cx.global::<Model<Self>>().clone())
} else {
None
}
@ -590,7 +590,7 @@ impl Copilot {
}
}
pub fn register_buffer(&mut self, buffer: &Handle<Buffer>, cx: &mut ModelContext<Self>) {
pub fn register_buffer(&mut self, buffer: &Model<Buffer>, cx: &mut ModelContext<Self>) {
let weak_buffer = buffer.downgrade();
self.buffers.insert(weak_buffer.clone());
@ -646,7 +646,7 @@ impl Copilot {
fn handle_buffer_event(
&mut self,
buffer: Handle<Buffer>,
buffer: Model<Buffer>,
event: &language2::Event,
cx: &mut ModelContext<Self>,
) -> Result<()> {
@ -723,7 +723,7 @@ impl Copilot {
pub fn completions<T>(
&mut self,
buffer: &Handle<Buffer>,
buffer: &Model<Buffer>,
position: T,
cx: &mut ModelContext<Self>,
) -> Task<Result<Vec<Completion>>>
@ -735,7 +735,7 @@ impl Copilot {
pub fn completions_cycling<T>(
&mut self,
buffer: &Handle<Buffer>,
buffer: &Model<Buffer>,
position: T,
cx: &mut ModelContext<Self>,
) -> Task<Result<Vec<Completion>>>
@ -792,7 +792,7 @@ impl Copilot {
fn request_completions<R, T>(
&mut self,
buffer: &Handle<Buffer>,
buffer: &Model<Buffer>,
position: T,
cx: &mut ModelContext<Self>,
) -> Task<Result<Vec<Completion>>>
@ -926,7 +926,7 @@ fn id_for_language(language: Option<&Arc<Language>>) -> String {
}
}
fn uri_for_buffer(buffer: &Handle<Buffer>, cx: &AppContext) -> lsp2::Url {
fn uri_for_buffer(buffer: &Model<Buffer>, cx: &AppContext) -> lsp2::Url {
if let Some(file) = buffer.read(cx).file().and_then(|file| file.as_local()) {
lsp2::Url::from_file_path(file.abs_path(cx)).unwrap()
} else {

View file

@ -707,19 +707,19 @@ impl AppContext {
}
impl Context for AppContext {
type EntityContext<'a, T> = ModelContext<'a, T>;
type ModelContext<'a, T> = ModelContext<'a, T>;
type Result<T> = T;
/// Build an entity that is owned by the application. The given function will be invoked with
/// a `ModelContext` and must return an object representing the entity. A `Handle` will be returned
/// which can be used to access the entity in a context.
fn entity<T: 'static + Send>(
fn build_model<T: 'static + Send>(
&mut self,
build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T,
) -> Handle<T> {
build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T,
) -> Model<T> {
self.update(|cx| {
let slot = cx.entities.reserve();
let entity = build_entity(&mut ModelContext::mutable(cx, slot.downgrade()));
let entity = build_model(&mut ModelContext::mutable(cx, slot.downgrade()));
cx.entities.insert(slot, entity)
})
}
@ -728,8 +728,8 @@ impl Context for AppContext {
/// entity along with a `ModelContext` for the entity.
fn update_entity<T: 'static, R>(
&mut self,
handle: &Handle<T>,
update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R,
handle: &Model<T>,
update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R,
) -> R {
self.update(|cx| {
let mut entity = cx.entities.lease(handle);

View file

@ -1,5 +1,5 @@
use crate::{
AnyWindowHandle, AppContext, Context, Executor, Handle, MainThread, ModelContext, Result, Task,
AnyWindowHandle, AppContext, Context, Executor, MainThread, Model, ModelContext, Result, Task,
WindowContext,
};
use anyhow::anyhow;
@ -14,13 +14,13 @@ pub struct AsyncAppContext {
}
impl Context for AsyncAppContext {
type EntityContext<'a, T> = ModelContext<'a, T>;
type ModelContext<'a, T> = ModelContext<'a, T>;
type Result<T> = Result<T>;
fn entity<T: 'static>(
fn build_model<T: 'static>(
&mut self,
build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T,
) -> Self::Result<Handle<T>>
build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T,
) -> Self::Result<Model<T>>
where
T: 'static + Send,
{
@ -29,13 +29,13 @@ impl Context for AsyncAppContext {
.upgrade()
.ok_or_else(|| anyhow!("app was released"))?;
let mut lock = app.lock(); // Need this to compile
Ok(lock.entity(build_entity))
Ok(lock.build_model(build_model))
}
fn update_entity<T: 'static, R>(
&mut self,
handle: &Handle<T>,
update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R,
handle: &Model<T>,
update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R,
) -> Self::Result<R> {
let app = self
.app
@ -216,24 +216,24 @@ impl AsyncWindowContext {
}
impl Context for AsyncWindowContext {
type EntityContext<'a, T> = ModelContext<'a, T>;
type ModelContext<'a, T> = ModelContext<'a, T>;
type Result<T> = Result<T>;
fn entity<T>(
fn build_model<T>(
&mut self,
build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T,
) -> Result<Handle<T>>
build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T,
) -> Result<Model<T>>
where
T: 'static + Send,
{
self.app
.update_window(self.window, |cx| cx.entity(build_entity))
.update_window(self.window, |cx| cx.build_model(build_model))
}
fn update_entity<T: 'static, R>(
&mut self,
handle: &Handle<T>,
update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R,
handle: &Model<T>,
update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R,
) -> Result<R> {
self.app
.update_window(self.window, |cx| cx.update_entity(handle, update))

View file

@ -53,11 +53,11 @@ impl EntityMap {
/// Reserve a slot for an entity, which you can subsequently use with `insert`.
pub fn reserve<T: 'static>(&self) -> Slot<T> {
let id = self.ref_counts.write().counts.insert(1.into());
Slot(Handle::new(id, Arc::downgrade(&self.ref_counts)))
Slot(Model::new(id, Arc::downgrade(&self.ref_counts)))
}
/// Insert an entity into a slot obtained by calling `reserve`.
pub fn insert<T>(&mut self, slot: Slot<T>, entity: T) -> Handle<T>
pub fn insert<T>(&mut self, slot: Slot<T>, entity: T) -> Model<T>
where
T: 'static + Send,
{
@ -67,7 +67,7 @@ impl EntityMap {
}
/// Move an entity to the stack.
pub fn lease<'a, T>(&mut self, handle: &'a Handle<T>) -> Lease<'a, T> {
pub fn lease<'a, T>(&mut self, handle: &'a Model<T>) -> Lease<'a, T> {
self.assert_valid_context(handle);
let entity = Some(
self.entities
@ -87,7 +87,7 @@ impl EntityMap {
.insert(lease.handle.entity_id, lease.entity.take().unwrap());
}
pub fn read<T: 'static>(&self, handle: &Handle<T>) -> &T {
pub fn read<T: 'static>(&self, handle: &Model<T>) -> &T {
self.assert_valid_context(handle);
self.entities[handle.entity_id].downcast_ref().unwrap()
}
@ -115,7 +115,7 @@ impl EntityMap {
pub struct Lease<'a, T> {
entity: Option<AnyBox>,
pub handle: &'a Handle<T>,
pub handle: &'a Model<T>,
entity_type: PhantomData<T>,
}
@ -143,7 +143,7 @@ impl<'a, T> Drop for Lease<'a, T> {
}
#[derive(Deref, DerefMut)]
pub struct Slot<T>(Handle<T>);
pub struct Slot<T>(Model<T>);
pub struct AnyHandle {
pub(crate) entity_id: EntityId,
@ -172,9 +172,9 @@ impl AnyHandle {
}
}
pub fn downcast<T: 'static>(&self) -> Option<Handle<T>> {
pub fn downcast<T: 'static>(&self) -> Option<Model<T>> {
if TypeId::of::<T>() == self.entity_type {
Some(Handle {
Some(Model {
any_handle: self.clone(),
entity_type: PhantomData,
})
@ -223,8 +223,8 @@ impl Drop for AnyHandle {
}
}
impl<T> From<Handle<T>> for AnyHandle {
fn from(handle: Handle<T>) -> Self {
impl<T> From<Model<T>> for AnyHandle {
fn from(handle: Model<T>) -> Self {
handle.any_handle
}
}
@ -244,17 +244,17 @@ impl PartialEq for AnyHandle {
impl Eq for AnyHandle {}
#[derive(Deref, DerefMut)]
pub struct Handle<T> {
pub struct Model<T> {
#[deref]
#[deref_mut]
any_handle: AnyHandle,
entity_type: PhantomData<T>,
}
unsafe impl<T> Send for Handle<T> {}
unsafe impl<T> Sync for Handle<T> {}
unsafe impl<T> Send for Model<T> {}
unsafe impl<T> Sync for Model<T> {}
impl<T: 'static> Handle<T> {
impl<T: 'static> Model<T> {
fn new(id: EntityId, entity_map: Weak<RwLock<EntityRefCounts>>) -> Self
where
T: 'static,
@ -284,7 +284,7 @@ impl<T: 'static> Handle<T> {
pub fn update<C, R>(
&self,
cx: &mut C,
update: impl FnOnce(&mut T, &mut C::EntityContext<'_, T>) -> R,
update: impl FnOnce(&mut T, &mut C::ModelContext<'_, T>) -> R,
) -> C::Result<R>
where
C: Context,
@ -293,7 +293,7 @@ impl<T: 'static> Handle<T> {
}
}
impl<T> Clone for Handle<T> {
impl<T> Clone for Model<T> {
fn clone(&self) -> Self {
Self {
any_handle: self.any_handle.clone(),
@ -302,7 +302,7 @@ impl<T> Clone for Handle<T> {
}
}
impl<T> std::fmt::Debug for Handle<T> {
impl<T> std::fmt::Debug for Model<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
@ -313,21 +313,21 @@ impl<T> std::fmt::Debug for Handle<T> {
}
}
impl<T> Hash for Handle<T> {
impl<T> Hash for Model<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.any_handle.hash(state);
}
}
impl<T> PartialEq for Handle<T> {
impl<T> PartialEq for Model<T> {
fn eq(&self, other: &Self) -> bool {
self.any_handle == other.any_handle
}
}
impl<T> Eq for Handle<T> {}
impl<T> Eq for Model<T> {}
impl<T> PartialEq<WeakHandle<T>> for Handle<T> {
impl<T> PartialEq<WeakHandle<T>> for Model<T> {
fn eq(&self, other: &WeakHandle<T>) -> bool {
self.entity_id() == other.entity_id()
}
@ -410,8 +410,8 @@ impl<T> Clone for WeakHandle<T> {
}
impl<T: 'static> WeakHandle<T> {
pub fn upgrade(&self) -> Option<Handle<T>> {
Some(Handle {
pub fn upgrade(&self) -> Option<Model<T>> {
Some(Model {
any_handle: self.any_handle.upgrade()?,
entity_type: self.entity_type,
})
@ -427,7 +427,7 @@ impl<T: 'static> WeakHandle<T> {
pub fn update<C, R>(
&self,
cx: &mut C,
update: impl FnOnce(&mut T, &mut C::EntityContext<'_, T>) -> R,
update: impl FnOnce(&mut T, &mut C::ModelContext<'_, T>) -> R,
) -> Result<R>
where
C: Context,
@ -455,8 +455,8 @@ impl<T> PartialEq for WeakHandle<T> {
impl<T> Eq for WeakHandle<T> {}
impl<T> PartialEq<Handle<T>> for WeakHandle<T> {
fn eq(&self, other: &Handle<T>) -> bool {
impl<T> PartialEq<Model<T>> for WeakHandle<T> {
fn eq(&self, other: &Model<T>) -> bool {
self.entity_id() == other.entity_id()
}
}

View file

@ -1,5 +1,5 @@
use crate::{
AppContext, AsyncAppContext, Context, Effect, EntityId, EventEmitter, Handle, MainThread,
AppContext, AsyncAppContext, Context, Effect, EntityId, EventEmitter, MainThread, Model,
Reference, Subscription, Task, WeakHandle,
};
use derive_more::{Deref, DerefMut};
@ -30,7 +30,7 @@ impl<'a, T: 'static> ModelContext<'a, T> {
self.model_state.entity_id
}
pub fn handle(&self) -> Handle<T> {
pub fn handle(&self) -> Model<T> {
self.weak_handle()
.upgrade()
.expect("The entity must be alive if we have a model context")
@ -42,8 +42,8 @@ impl<'a, T: 'static> ModelContext<'a, T> {
pub fn observe<T2: 'static>(
&mut self,
handle: &Handle<T2>,
mut on_notify: impl FnMut(&mut T, Handle<T2>, &mut ModelContext<'_, T>) + Send + 'static,
handle: &Model<T2>,
mut on_notify: impl FnMut(&mut T, Model<T2>, &mut ModelContext<'_, T>) + Send + 'static,
) -> Subscription
where
T: 'static + Send,
@ -65,10 +65,8 @@ impl<'a, T: 'static> ModelContext<'a, T> {
pub fn subscribe<E: 'static + EventEmitter>(
&mut self,
handle: &Handle<E>,
mut on_event: impl FnMut(&mut T, Handle<E>, &E::Event, &mut ModelContext<'_, T>)
+ Send
+ 'static,
handle: &Model<E>,
mut on_event: impl FnMut(&mut T, Model<E>, &E::Event, &mut ModelContext<'_, T>) + Send + 'static,
) -> Subscription
where
T: 'static + Send,
@ -107,7 +105,7 @@ impl<'a, T: 'static> ModelContext<'a, T> {
pub fn observe_release<E: 'static>(
&mut self,
handle: &Handle<E>,
handle: &Model<E>,
mut on_release: impl FnMut(&mut T, &mut E, &mut ModelContext<'_, T>) + Send + 'static,
) -> Subscription
where
@ -224,23 +222,23 @@ where
}
impl<'a, T> Context for ModelContext<'a, T> {
type EntityContext<'b, U> = ModelContext<'b, U>;
type ModelContext<'b, U> = ModelContext<'b, U>;
type Result<U> = U;
fn entity<U>(
fn build_model<U>(
&mut self,
build_entity: impl FnOnce(&mut Self::EntityContext<'_, U>) -> U,
) -> Handle<U>
build_model: impl FnOnce(&mut Self::ModelContext<'_, U>) -> U,
) -> Model<U>
where
U: 'static + Send,
{
self.app.entity(build_entity)
self.app.build_model(build_model)
}
fn update_entity<U: 'static, R>(
&mut self,
handle: &Handle<U>,
update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, U>) -> R,
handle: &Model<U>,
update: impl FnOnce(&mut U, &mut Self::ModelContext<'_, U>) -> R,
) -> R {
self.app.update_entity(handle, update)
}

View file

@ -1,5 +1,5 @@
use crate::{
AnyWindowHandle, AppContext, AsyncAppContext, Context, Executor, Handle, MainThread,
AnyWindowHandle, AppContext, AsyncAppContext, Context, Executor, MainThread, Model,
ModelContext, Result, Task, TestDispatcher, TestPlatform, WindowContext,
};
use parking_lot::Mutex;
@ -12,24 +12,24 @@ pub struct TestAppContext {
}
impl Context for TestAppContext {
type EntityContext<'a, T> = ModelContext<'a, T>;
type ModelContext<'a, T> = ModelContext<'a, T>;
type Result<T> = T;
fn entity<T: 'static>(
fn build_model<T: 'static>(
&mut self,
build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T,
) -> Self::Result<Handle<T>>
build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T,
) -> Self::Result<Model<T>>
where
T: 'static + Send,
{
let mut lock = self.app.lock();
lock.entity(build_entity)
lock.build_model(build_model)
}
fn update_entity<T: 'static, R>(
&mut self,
handle: &Handle<T>,
update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R,
handle: &Model<T>,
update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R,
) -> Self::Result<R> {
let mut lock = self.app.lock();
lock.update_entity(handle, update)

View file

@ -70,20 +70,20 @@ use taffy::TaffyLayoutEngine;
type AnyBox = Box<dyn Any + Send>;
pub trait Context {
type EntityContext<'a, T>;
type ModelContext<'a, T>;
type Result<T>;
fn entity<T>(
fn build_model<T>(
&mut self,
build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T,
) -> Self::Result<Handle<T>>
build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T,
) -> Self::Result<Model<T>>
where
T: 'static + Send;
fn update_entity<T: 'static, R>(
&mut self,
handle: &Handle<T>,
update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R,
handle: &Model<T>,
update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R,
) -> Self::Result<R>;
}
@ -92,7 +92,7 @@ pub trait VisualContext: Context {
fn build_view<E, V>(
&mut self,
build_entity: impl FnOnce(&mut Self::ViewContext<'_, '_, V>) -> V,
build_model: impl FnOnce(&mut Self::ViewContext<'_, '_, V>) -> V,
render: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static,
) -> Self::Result<View<V>>
where
@ -130,37 +130,37 @@ impl<T> DerefMut for MainThread<T> {
}
impl<C: Context> Context for MainThread<C> {
type EntityContext<'a, T> = MainThread<C::EntityContext<'a, T>>;
type ModelContext<'a, T> = MainThread<C::ModelContext<'a, T>>;
type Result<T> = C::Result<T>;
fn entity<T>(
fn build_model<T>(
&mut self,
build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T,
) -> Self::Result<Handle<T>>
build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T,
) -> Self::Result<Model<T>>
where
T: 'static + Send,
{
self.0.entity(|cx| {
self.0.build_model(|cx| {
let cx = unsafe {
mem::transmute::<
&mut C::EntityContext<'_, T>,
&mut MainThread<C::EntityContext<'_, T>>,
&mut C::ModelContext<'_, T>,
&mut MainThread<C::ModelContext<'_, T>>,
>(cx)
};
build_entity(cx)
build_model(cx)
})
}
fn update_entity<T: 'static, R>(
&mut self,
handle: &Handle<T>,
update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R,
handle: &Model<T>,
update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R,
) -> Self::Result<R> {
self.0.update_entity(handle, |entity, cx| {
let cx = unsafe {
mem::transmute::<
&mut C::EntityContext<'_, T>,
&mut MainThread<C::EntityContext<'_, T>>,
&mut C::ModelContext<'_, T>,
&mut MainThread<C::ModelContext<'_, T>>,
>(cx)
};
update(entity, cx)
@ -173,7 +173,7 @@ impl<C: VisualContext> VisualContext for MainThread<C> {
fn build_view<E, V>(
&mut self,
build_entity: impl FnOnce(&mut Self::ViewContext<'_, '_, V>) -> V,
build_model: impl FnOnce(&mut Self::ViewContext<'_, '_, V>) -> V,
render: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static,
) -> Self::Result<View<V>>
where
@ -188,7 +188,7 @@ impl<C: VisualContext> VisualContext for MainThread<C> {
&mut MainThread<C::ViewContext<'_, '_, V>>,
>(cx)
};
build_entity(cx)
build_model(cx)
},
render,
)

View file

@ -1,7 +1,6 @@
use crate::{
AnyBox, AnyElement, AvailableSpace, BorrowWindow, Bounds, Component, Element, ElementId,
EntityId, Handle, LayoutId, Pixels, Size, ViewContext, VisualContext, WeakHandle,
WindowContext,
EntityId, LayoutId, Model, Pixels, Size, ViewContext, VisualContext, WeakHandle, WindowContext,
};
use anyhow::{Context, Result};
use parking_lot::Mutex;
@ -11,13 +10,13 @@ use std::{
};
pub struct View<V> {
pub(crate) state: Handle<V>,
pub(crate) state: Model<V>,
render: Arc<Mutex<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyElement<V> + Send + 'static>>,
}
impl<V: 'static> View<V> {
pub fn for_handle<E>(
state: Handle<V>,
state: Model<V>,
render: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static,
) -> View<V>
where

View file

@ -2,8 +2,8 @@ use crate::{
px, size, Action, AnyBox, AnyDrag, AnyView, AppContext, AsyncWindowContext, AvailableSpace,
Bounds, BoxShadow, Context, Corners, DevicePixels, DispatchContext, DisplayId, Edges, Effect,
EntityId, EventEmitter, ExternalPaths, FileDropEvent, FocusEvent, FontId, GlobalElementId,
GlyphId, Handle, Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch, KeyMatcher,
Keystroke, LayoutId, MainThread, MainThreadOnly, ModelContext, Modifiers, MonochromeSprite,
GlyphId, Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch, KeyMatcher, Keystroke,
LayoutId, MainThread, MainThreadOnly, Model, ModelContext, Modifiers, MonochromeSprite,
MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas,
PlatformWindow, Point, PolychromeSprite, Quad, Reference, RenderGlyphParams, RenderImageParams,
RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size, Style, Subscription,
@ -1240,25 +1240,25 @@ impl<'a, 'w> WindowContext<'a, 'w> {
}
impl Context for WindowContext<'_, '_> {
type EntityContext<'a, T> = ModelContext<'a, T>;
type ModelContext<'a, T> = ModelContext<'a, T>;
type Result<T> = T;
fn entity<T>(
fn build_model<T>(
&mut self,
build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T,
) -> Handle<T>
build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T,
) -> Model<T>
where
T: 'static + Send,
{
let slot = self.app.entities.reserve();
let entity = build_entity(&mut ModelContext::mutable(&mut *self.app, slot.downgrade()));
self.entities.insert(slot, entity)
let model = build_model(&mut ModelContext::mutable(&mut *self.app, slot.downgrade()));
self.entities.insert(slot, model)
}
fn update_entity<T: 'static, R>(
&mut self,
handle: &Handle<T>,
update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R,
handle: &Model<T>,
update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R,
) -> R {
let mut entity = self.entities.lease(handle);
let result = update(
@ -1576,8 +1576,8 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
pub fn observe<E>(
&mut self,
handle: &Handle<E>,
mut on_notify: impl FnMut(&mut V, Handle<E>, &mut ViewContext<'_, '_, V>) + Send + 'static,
handle: &Model<E>,
mut on_notify: impl FnMut(&mut V, Model<E>, &mut ViewContext<'_, '_, V>) + Send + 'static,
) -> Subscription
where
E: 'static,
@ -1604,8 +1604,8 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
pub fn subscribe<E: EventEmitter>(
&mut self,
handle: &Handle<E>,
mut on_event: impl FnMut(&mut V, Handle<E>, &E::Event, &mut ViewContext<'_, '_, V>)
handle: &Model<E>,
mut on_event: impl FnMut(&mut V, Model<E>, &E::Event, &mut ViewContext<'_, '_, V>)
+ Send
+ 'static,
) -> Subscription {
@ -1646,7 +1646,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
pub fn observe_release<T: 'static>(
&mut self,
handle: &Handle<T>,
handle: &Model<T>,
mut on_release: impl FnMut(&mut V, &mut T, &mut ViewContext<'_, '_, V>) + Send + 'static,
) -> Subscription
where
@ -1857,23 +1857,23 @@ where
}
impl<'a, 'w, V> Context for ViewContext<'a, 'w, V> {
type EntityContext<'b, U> = ModelContext<'b, U>;
type ModelContext<'b, U> = ModelContext<'b, U>;
type Result<U> = U;
fn entity<T>(
fn build_model<T>(
&mut self,
build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T,
) -> Handle<T>
build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T,
) -> Model<T>
where
T: 'static + Send,
{
self.window_cx.entity(build_entity)
self.window_cx.build_model(build_model)
}
fn update_entity<T: 'static, R>(
&mut self,
handle: &Handle<T>,
update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R,
handle: &Model<T>,
update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R,
) -> R {
self.window_cx.update_entity(handle, update)
}
@ -1884,14 +1884,14 @@ impl<V: 'static> VisualContext for ViewContext<'_, '_, V> {
fn build_view<E, V2>(
&mut self,
build_entity: impl FnOnce(&mut Self::ViewContext<'_, '_, V2>) -> V2,
build_view: impl FnOnce(&mut Self::ViewContext<'_, '_, V2>) -> V2,
render: impl Fn(&mut V2, &mut ViewContext<'_, '_, V2>) -> E + Send + 'static,
) -> Self::Result<View<V2>>
where
E: crate::Component<V2>,
V2: 'static + Send,
{
self.window_cx.build_view(build_entity, render)
self.window_cx.build_view(build_view, render)
}
fn update_view<V2: 'static, R>(

View file

@ -5,7 +5,7 @@ use crate::language_settings::{
use crate::Buffer;
use clock::ReplicaId;
use collections::BTreeMap;
use gpui2::{AppContext, Handle};
use gpui2::{AppContext, Model};
use gpui2::{Context, TestAppContext};
use indoc::indoc;
use proto::deserialize_operation;
@ -42,7 +42,7 @@ fn init_logger() {
fn test_line_endings(cx: &mut gpui2::AppContext) {
init_settings(cx, |_| {});
cx.entity(|cx| {
cx.build_model(|cx| {
let mut buffer = Buffer::new(0, cx.entity_id().as_u64(), "one\r\ntwo\rthree")
.with_language(Arc::new(rust_lang()), cx);
assert_eq!(buffer.text(), "one\ntwo\nthree");
@ -138,8 +138,8 @@ fn test_edit_events(cx: &mut gpui2::AppContext) {
let buffer_1_events = Arc::new(Mutex::new(Vec::new()));
let buffer_2_events = Arc::new(Mutex::new(Vec::new()));
let buffer1 = cx.entity(|cx| Buffer::new(0, cx.entity_id().as_u64(), "abcdef"));
let buffer2 = cx.entity(|cx| Buffer::new(1, cx.entity_id().as_u64(), "abcdef"));
let buffer1 = cx.build_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "abcdef"));
let buffer2 = cx.build_model(|cx| Buffer::new(1, cx.entity_id().as_u64(), "abcdef"));
let buffer1_ops = Arc::new(Mutex::new(Vec::new()));
buffer1.update(cx, {
let buffer1_ops = buffer1_ops.clone();
@ -218,7 +218,7 @@ fn test_edit_events(cx: &mut gpui2::AppContext) {
#[gpui2::test]
async fn test_apply_diff(cx: &mut TestAppContext) {
let text = "a\nbb\nccc\ndddd\neeeee\nffffff\n";
let buffer = cx.entity(|cx| Buffer::new(0, cx.entity_id().as_u64(), text));
let buffer = cx.build_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), text));
let anchor = buffer.update(cx, |buffer, _| buffer.anchor_before(Point::new(3, 3)));
let text = "a\nccc\ndddd\nffffff\n";
@ -250,7 +250,7 @@ async fn test_normalize_whitespace(cx: &mut gpui2::TestAppContext) {
]
.join("\n");
let buffer = cx.entity(|cx| Buffer::new(0, cx.entity_id().as_u64(), text));
let buffer = cx.build_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), text));
// Spawn a task to format the buffer's whitespace.
// Pause so that the foratting task starts running.
@ -314,7 +314,7 @@ async fn test_normalize_whitespace(cx: &mut gpui2::TestAppContext) {
#[gpui2::test]
async fn test_reparse(cx: &mut gpui2::TestAppContext) {
let text = "fn a() {}";
let buffer = cx.entity(|cx| {
let buffer = cx.build_model(|cx| {
Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx)
});
@ -442,7 +442,7 @@ async fn test_reparse(cx: &mut gpui2::TestAppContext) {
#[gpui2::test]
async fn test_resetting_language(cx: &mut gpui2::TestAppContext) {
let buffer = cx.entity(|cx| {
let buffer = cx.build_model(|cx| {
let mut buffer =
Buffer::new(0, cx.entity_id().as_u64(), "{}").with_language(Arc::new(rust_lang()), cx);
buffer.set_sync_parse_timeout(Duration::ZERO);
@ -492,7 +492,7 @@ async fn test_outline(cx: &mut gpui2::TestAppContext) {
"#
.unindent();
let buffer = cx.entity(|cx| {
let buffer = cx.build_model(|cx| {
Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx)
});
let outline = buffer
@ -578,7 +578,7 @@ async fn test_outline_nodes_with_newlines(cx: &mut gpui2::TestAppContext) {
"#
.unindent();
let buffer = cx.entity(|cx| {
let buffer = cx.build_model(|cx| {
Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx)
});
let outline = buffer
@ -616,7 +616,7 @@ async fn test_outline_with_extra_context(cx: &mut gpui2::TestAppContext) {
"#
.unindent();
let buffer = cx.entity(|cx| {
let buffer = cx.build_model(|cx| {
Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(language), cx)
});
let snapshot = buffer.update(cx, |buffer, _| buffer.snapshot());
@ -660,7 +660,7 @@ async fn test_symbols_containing(cx: &mut gpui2::TestAppContext) {
"#
.unindent();
let buffer = cx.entity(|cx| {
let buffer = cx.build_model(|cx| {
Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx)
});
let snapshot = buffer.update(cx, |buffer, _| buffer.snapshot());
@ -881,7 +881,7 @@ fn test_enclosing_bracket_ranges_where_brackets_are_not_outermost_children(cx: &
#[gpui2::test]
fn test_range_for_syntax_ancestor(cx: &mut AppContext) {
cx.entity(|cx| {
cx.build_model(|cx| {
let text = "fn a() { b(|c| {}) }";
let buffer =
Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx);
@ -922,7 +922,7 @@ fn test_range_for_syntax_ancestor(cx: &mut AppContext) {
fn test_autoindent_with_soft_tabs(cx: &mut AppContext) {
init_settings(cx, |_| {});
cx.entity(|cx| {
cx.build_model(|cx| {
let text = "fn a() {}";
let mut buffer =
Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx);
@ -965,7 +965,7 @@ fn test_autoindent_with_hard_tabs(cx: &mut AppContext) {
settings.defaults.hard_tabs = Some(true);
});
cx.entity(|cx| {
cx.build_model(|cx| {
let text = "fn a() {}";
let mut buffer =
Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx);
@ -1006,7 +1006,7 @@ fn test_autoindent_with_hard_tabs(cx: &mut AppContext) {
fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut AppContext) {
init_settings(cx, |_| {});
cx.entity(|cx| {
cx.build_model(|cx| {
let entity_id = cx.entity_id();
let mut buffer = Buffer::new(
0,
@ -1080,7 +1080,7 @@ fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut AppC
buffer
});
cx.entity(|cx| {
cx.build_model(|cx| {
eprintln!("second buffer: {:?}", cx.entity_id());
let mut buffer = Buffer::new(
@ -1147,7 +1147,7 @@ fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut AppC
fn test_autoindent_does_not_adjust_lines_within_newly_created_errors(cx: &mut AppContext) {
init_settings(cx, |_| {});
cx.entity(|cx| {
cx.build_model(|cx| {
let mut buffer = Buffer::new(
0,
cx.entity_id().as_u64(),
@ -1209,7 +1209,7 @@ fn test_autoindent_does_not_adjust_lines_within_newly_created_errors(cx: &mut Ap
fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut AppContext) {
init_settings(cx, |_| {});
cx.entity(|cx| {
cx.build_model(|cx| {
let mut buffer = Buffer::new(
0,
cx.entity_id().as_u64(),
@ -1266,7 +1266,7 @@ fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut AppContext) {
fn test_autoindent_with_edit_at_end_of_buffer(cx: &mut AppContext) {
init_settings(cx, |_| {});
cx.entity(|cx| {
cx.build_model(|cx| {
let text = "a\nb";
let mut buffer =
Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx);
@ -1284,7 +1284,7 @@ fn test_autoindent_with_edit_at_end_of_buffer(cx: &mut AppContext) {
fn test_autoindent_multi_line_insertion(cx: &mut AppContext) {
init_settings(cx, |_| {});
cx.entity(|cx| {
cx.build_model(|cx| {
let text = "
const a: usize = 1;
fn b() {
@ -1326,7 +1326,7 @@ fn test_autoindent_multi_line_insertion(cx: &mut AppContext) {
fn test_autoindent_block_mode(cx: &mut AppContext) {
init_settings(cx, |_| {});
cx.entity(|cx| {
cx.build_model(|cx| {
let text = r#"
fn a() {
b();
@ -1410,7 +1410,7 @@ fn test_autoindent_block_mode(cx: &mut AppContext) {
fn test_autoindent_block_mode_without_original_indent_columns(cx: &mut AppContext) {
init_settings(cx, |_| {});
cx.entity(|cx| {
cx.build_model(|cx| {
let text = r#"
fn a() {
if b() {
@ -1490,7 +1490,7 @@ fn test_autoindent_block_mode_without_original_indent_columns(cx: &mut AppContex
fn test_autoindent_language_without_indents_query(cx: &mut AppContext) {
init_settings(cx, |_| {});
cx.entity(|cx| {
cx.build_model(|cx| {
let text = "
* one
- a
@ -1559,7 +1559,7 @@ fn test_autoindent_with_injected_languages(cx: &mut AppContext) {
language_registry.add(html_language.clone());
language_registry.add(javascript_language.clone());
cx.entity(|cx| {
cx.build_model(|cx| {
let (text, ranges) = marked_text_ranges(
&"
<div>ˇ
@ -1610,7 +1610,7 @@ fn test_autoindent_query_with_outdent_captures(cx: &mut AppContext) {
settings.defaults.tab_size = Some(2.try_into().unwrap());
});
cx.entity(|cx| {
cx.build_model(|cx| {
let mut buffer =
Buffer::new(0, cx.entity_id().as_u64(), "").with_language(Arc::new(ruby_lang()), cx);
@ -1653,7 +1653,7 @@ fn test_autoindent_query_with_outdent_captures(cx: &mut AppContext) {
fn test_language_scope_at_with_javascript(cx: &mut AppContext) {
init_settings(cx, |_| {});
cx.entity(|cx| {
cx.build_model(|cx| {
let language = Language::new(
LanguageConfig {
name: "JavaScript".into(),
@ -1742,7 +1742,7 @@ fn test_language_scope_at_with_javascript(cx: &mut AppContext) {
fn test_language_scope_at_with_rust(cx: &mut AppContext) {
init_settings(cx, |_| {});
cx.entity(|cx| {
cx.build_model(|cx| {
let language = Language::new(
LanguageConfig {
name: "Rust".into(),
@ -1810,7 +1810,7 @@ fn test_language_scope_at_with_rust(cx: &mut AppContext) {
fn test_language_scope_at_with_combined_injections(cx: &mut AppContext) {
init_settings(cx, |_| {});
cx.entity(|cx| {
cx.build_model(|cx| {
let text = r#"
<ol>
<% people.each do |person| %>
@ -1858,7 +1858,7 @@ fn test_language_scope_at_with_combined_injections(cx: &mut AppContext) {
fn test_serialization(cx: &mut gpui2::AppContext) {
let mut now = Instant::now();
let buffer1 = cx.entity(|cx| {
let buffer1 = cx.build_model(|cx| {
let mut buffer = Buffer::new(0, cx.entity_id().as_u64(), "abc");
buffer.edit([(3..3, "D")], None, cx);
@ -1881,7 +1881,7 @@ fn test_serialization(cx: &mut gpui2::AppContext) {
let ops = cx
.executor()
.block(buffer1.read(cx).serialize_ops(None, cx));
let buffer2 = cx.entity(|cx| {
let buffer2 = cx.build_model(|cx| {
let mut buffer = Buffer::from_proto(1, state, None).unwrap();
buffer
.apply_ops(
@ -1914,10 +1914,11 @@ fn test_random_collaboration(cx: &mut AppContext, mut rng: StdRng) {
let mut replica_ids = Vec::new();
let mut buffers = Vec::new();
let network = Arc::new(Mutex::new(Network::new(rng.clone())));
let base_buffer = cx.entity(|cx| Buffer::new(0, cx.entity_id().as_u64(), base_text.as_str()));
let base_buffer =
cx.build_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), base_text.as_str()));
for i in 0..rng.gen_range(min_peers..=max_peers) {
let buffer = cx.entity(|cx| {
let buffer = cx.build_model(|cx| {
let state = base_buffer.read(cx).to_proto();
let ops = cx
.executor()
@ -2034,7 +2035,7 @@ fn test_random_collaboration(cx: &mut AppContext, mut rng: StdRng) {
new_replica_id,
replica_id
);
new_buffer = Some(cx.entity(|cx| {
new_buffer = Some(cx.build_model(|cx| {
let mut new_buffer =
Buffer::from_proto(new_replica_id, old_buffer_state, None).unwrap();
new_buffer
@ -2396,7 +2397,7 @@ fn javascript_lang() -> Language {
.unwrap()
}
fn get_tree_sexp(buffer: &Handle<Buffer>, cx: &mut gpui2::TestAppContext) -> String {
fn get_tree_sexp(buffer: &Model<Buffer>, cx: &mut gpui2::TestAppContext) -> String {
buffer.update(cx, |buffer, _| {
let snapshot = buffer.snapshot();
let layers = snapshot.syntax.layers(buffer.as_text_snapshot());
@ -2412,7 +2413,7 @@ fn assert_bracket_pairs(
cx: &mut AppContext,
) {
let (expected_text, selection_ranges) = marked_text_ranges(selection_text, false);
let buffer = cx.entity(|cx| {
let buffer = cx.build_model(|cx| {
Buffer::new(0, cx.entity_id().as_u64(), expected_text.clone())
.with_language(Arc::new(language), cx)
});

View file

@ -1,7 +1,7 @@
use anyhow::Context;
use collections::{HashMap, HashSet};
use fs::Fs;
use gpui2::{AsyncAppContext, Handle};
use gpui2::{AsyncAppContext, Model};
use language2::{language_settings::language_settings, Buffer, BundledFormatter, Diff};
use lsp2::{LanguageServer, LanguageServerId};
use node_runtime::NodeRuntime;
@ -183,7 +183,7 @@ impl Prettier {
pub async fn format(
&self,
buffer: &Handle<Buffer>,
buffer: &Model<Buffer>,
buffer_path: Option<PathBuf>,
cx: &mut AsyncAppContext,
) -> anyhow::Result<Diff> {

View file

@ -7,7 +7,7 @@ use anyhow::{anyhow, Context, Result};
use async_trait::async_trait;
use client2::proto::{self, PeerId};
use futures::future;
use gpui2::{AppContext, AsyncAppContext, Handle};
use gpui2::{AppContext, AsyncAppContext, Model};
use language2::{
language_settings::{language_settings, InlayHintKind},
point_from_lsp, point_to_lsp,
@ -53,8 +53,8 @@ pub(crate) trait LspCommand: 'static + Sized + Send {
async fn response_from_lsp(
self,
message: <Self::LspRequest as lsp2::request::Request>::Result,
project: Handle<Project>,
buffer: Handle<Buffer>,
project: Model<Project>,
buffer: Model<Buffer>,
server_id: LanguageServerId,
cx: AsyncAppContext,
) -> Result<Self::Response>;
@ -63,8 +63,8 @@ pub(crate) trait LspCommand: 'static + Sized + Send {
async fn from_proto(
message: Self::ProtoRequest,
project: Handle<Project>,
buffer: Handle<Buffer>,
project: Model<Project>,
buffer: Model<Buffer>,
cx: AsyncAppContext,
) -> Result<Self>;
@ -79,8 +79,8 @@ pub(crate) trait LspCommand: 'static + Sized + Send {
async fn response_from_proto(
self,
message: <Self::ProtoRequest as proto::RequestMessage>::Response,
project: Handle<Project>,
buffer: Handle<Buffer>,
project: Model<Project>,
buffer: Model<Buffer>,
cx: AsyncAppContext,
) -> Result<Self::Response>;
@ -180,8 +180,8 @@ impl LspCommand for PrepareRename {
async fn response_from_lsp(
self,
message: Option<lsp2::PrepareRenameResponse>,
_: Handle<Project>,
buffer: Handle<Buffer>,
_: Model<Project>,
buffer: Model<Buffer>,
_: LanguageServerId,
mut cx: AsyncAppContext,
) -> Result<Option<Range<Anchor>>> {
@ -215,8 +215,8 @@ impl LspCommand for PrepareRename {
async fn from_proto(
message: proto::PrepareRename,
_: Handle<Project>,
buffer: Handle<Buffer>,
_: Model<Project>,
buffer: Model<Buffer>,
mut cx: AsyncAppContext,
) -> Result<Self> {
let position = message
@ -256,8 +256,8 @@ impl LspCommand for PrepareRename {
async fn response_from_proto(
self,
message: proto::PrepareRenameResponse,
_: Handle<Project>,
buffer: Handle<Buffer>,
_: Model<Project>,
buffer: Model<Buffer>,
mut cx: AsyncAppContext,
) -> Result<Option<Range<Anchor>>> {
if message.can_rename {
@ -307,8 +307,8 @@ impl LspCommand for PerformRename {
async fn response_from_lsp(
self,
message: Option<lsp2::WorkspaceEdit>,
project: Handle<Project>,
buffer: Handle<Buffer>,
project: Model<Project>,
buffer: Model<Buffer>,
server_id: LanguageServerId,
mut cx: AsyncAppContext,
) -> Result<ProjectTransaction> {
@ -343,8 +343,8 @@ impl LspCommand for PerformRename {
async fn from_proto(
message: proto::PerformRename,
_: Handle<Project>,
buffer: Handle<Buffer>,
_: Model<Project>,
buffer: Model<Buffer>,
mut cx: AsyncAppContext,
) -> Result<Self> {
let position = message
@ -379,8 +379,8 @@ impl LspCommand for PerformRename {
async fn response_from_proto(
self,
message: proto::PerformRenameResponse,
project: Handle<Project>,
_: Handle<Buffer>,
project: Model<Project>,
_: Model<Buffer>,
mut cx: AsyncAppContext,
) -> Result<ProjectTransaction> {
let message = message
@ -426,8 +426,8 @@ impl LspCommand for GetDefinition {
async fn response_from_lsp(
self,
message: Option<lsp2::GotoDefinitionResponse>,
project: Handle<Project>,
buffer: Handle<Buffer>,
project: Model<Project>,
buffer: Model<Buffer>,
server_id: LanguageServerId,
cx: AsyncAppContext,
) -> Result<Vec<LocationLink>> {
@ -447,8 +447,8 @@ impl LspCommand for GetDefinition {
async fn from_proto(
message: proto::GetDefinition,
_: Handle<Project>,
buffer: Handle<Buffer>,
_: Model<Project>,
buffer: Model<Buffer>,
mut cx: AsyncAppContext,
) -> Result<Self> {
let position = message
@ -479,8 +479,8 @@ impl LspCommand for GetDefinition {
async fn response_from_proto(
self,
message: proto::GetDefinitionResponse,
project: Handle<Project>,
_: Handle<Buffer>,
project: Model<Project>,
_: Model<Buffer>,
cx: AsyncAppContext,
) -> Result<Vec<LocationLink>> {
location_links_from_proto(message.links, project, cx).await
@ -527,8 +527,8 @@ impl LspCommand for GetTypeDefinition {
async fn response_from_lsp(
self,
message: Option<lsp2::GotoTypeDefinitionResponse>,
project: Handle<Project>,
buffer: Handle<Buffer>,
project: Model<Project>,
buffer: Model<Buffer>,
server_id: LanguageServerId,
cx: AsyncAppContext,
) -> Result<Vec<LocationLink>> {
@ -548,8 +548,8 @@ impl LspCommand for GetTypeDefinition {
async fn from_proto(
message: proto::GetTypeDefinition,
_: Handle<Project>,
buffer: Handle<Buffer>,
_: Model<Project>,
buffer: Model<Buffer>,
mut cx: AsyncAppContext,
) -> Result<Self> {
let position = message
@ -580,8 +580,8 @@ impl LspCommand for GetTypeDefinition {
async fn response_from_proto(
self,
message: proto::GetTypeDefinitionResponse,
project: Handle<Project>,
_: Handle<Buffer>,
project: Model<Project>,
_: Model<Buffer>,
cx: AsyncAppContext,
) -> Result<Vec<LocationLink>> {
location_links_from_proto(message.links, project, cx).await
@ -593,8 +593,8 @@ impl LspCommand for GetTypeDefinition {
}
fn language_server_for_buffer(
project: &Handle<Project>,
buffer: &Handle<Buffer>,
project: &Model<Project>,
buffer: &Model<Buffer>,
server_id: LanguageServerId,
cx: &mut AsyncAppContext,
) -> Result<(Arc<CachedLspAdapter>, Arc<LanguageServer>)> {
@ -609,7 +609,7 @@ fn language_server_for_buffer(
async fn location_links_from_proto(
proto_links: Vec<proto::LocationLink>,
project: Handle<Project>,
project: Model<Project>,
mut cx: AsyncAppContext,
) -> Result<Vec<LocationLink>> {
let mut links = Vec::new();
@ -671,8 +671,8 @@ async fn location_links_from_proto(
async fn location_links_from_lsp(
message: Option<lsp2::GotoDefinitionResponse>,
project: Handle<Project>,
buffer: Handle<Buffer>,
project: Model<Project>,
buffer: Model<Buffer>,
server_id: LanguageServerId,
mut cx: AsyncAppContext,
) -> Result<Vec<LocationLink>> {
@ -814,8 +814,8 @@ impl LspCommand for GetReferences {
async fn response_from_lsp(
self,
locations: Option<Vec<lsp2::Location>>,
project: Handle<Project>,
buffer: Handle<Buffer>,
project: Model<Project>,
buffer: Model<Buffer>,
server_id: LanguageServerId,
mut cx: AsyncAppContext,
) -> Result<Vec<Location>> {
@ -868,8 +868,8 @@ impl LspCommand for GetReferences {
async fn from_proto(
message: proto::GetReferences,
_: Handle<Project>,
buffer: Handle<Buffer>,
_: Model<Project>,
buffer: Model<Buffer>,
mut cx: AsyncAppContext,
) -> Result<Self> {
let position = message
@ -910,8 +910,8 @@ impl LspCommand for GetReferences {
async fn response_from_proto(
self,
message: proto::GetReferencesResponse,
project: Handle<Project>,
_: Handle<Buffer>,
project: Model<Project>,
_: Model<Buffer>,
mut cx: AsyncAppContext,
) -> Result<Vec<Location>> {
let mut locations = Vec::new();
@ -977,8 +977,8 @@ impl LspCommand for GetDocumentHighlights {
async fn response_from_lsp(
self,
lsp_highlights: Option<Vec<lsp2::DocumentHighlight>>,
_: Handle<Project>,
buffer: Handle<Buffer>,
_: Model<Project>,
buffer: Model<Buffer>,
_: LanguageServerId,
mut cx: AsyncAppContext,
) -> Result<Vec<DocumentHighlight>> {
@ -1016,8 +1016,8 @@ impl LspCommand for GetDocumentHighlights {
async fn from_proto(
message: proto::GetDocumentHighlights,
_: Handle<Project>,
buffer: Handle<Buffer>,
_: Model<Project>,
buffer: Model<Buffer>,
mut cx: AsyncAppContext,
) -> Result<Self> {
let position = message
@ -1060,8 +1060,8 @@ impl LspCommand for GetDocumentHighlights {
async fn response_from_proto(
self,
message: proto::GetDocumentHighlightsResponse,
_: Handle<Project>,
buffer: Handle<Buffer>,
_: Model<Project>,
buffer: Model<Buffer>,
mut cx: AsyncAppContext,
) -> Result<Vec<DocumentHighlight>> {
let mut highlights = Vec::new();
@ -1123,8 +1123,8 @@ impl LspCommand for GetHover {
async fn response_from_lsp(
self,
message: Option<lsp2::Hover>,
_: Handle<Project>,
buffer: Handle<Buffer>,
_: Model<Project>,
buffer: Model<Buffer>,
_: LanguageServerId,
mut cx: AsyncAppContext,
) -> Result<Self::Response> {
@ -1206,8 +1206,8 @@ impl LspCommand for GetHover {
async fn from_proto(
message: Self::ProtoRequest,
_: Handle<Project>,
buffer: Handle<Buffer>,
_: Model<Project>,
buffer: Model<Buffer>,
mut cx: AsyncAppContext,
) -> Result<Self> {
let position = message
@ -1272,8 +1272,8 @@ impl LspCommand for GetHover {
async fn response_from_proto(
self,
message: proto::GetHoverResponse,
_: Handle<Project>,
buffer: Handle<Buffer>,
_: Model<Project>,
buffer: Model<Buffer>,
mut cx: AsyncAppContext,
) -> Result<Self::Response> {
let contents: Vec<_> = message
@ -1341,8 +1341,8 @@ impl LspCommand for GetCompletions {
async fn response_from_lsp(
self,
completions: Option<lsp2::CompletionResponse>,
_: Handle<Project>,
buffer: Handle<Buffer>,
_: Model<Project>,
buffer: Model<Buffer>,
server_id: LanguageServerId,
mut cx: AsyncAppContext,
) -> Result<Vec<Completion>> {
@ -1484,8 +1484,8 @@ impl LspCommand for GetCompletions {
async fn from_proto(
message: proto::GetCompletions,
_: Handle<Project>,
buffer: Handle<Buffer>,
_: Model<Project>,
buffer: Model<Buffer>,
mut cx: AsyncAppContext,
) -> Result<Self> {
let version = deserialize_version(&message.version);
@ -1523,8 +1523,8 @@ impl LspCommand for GetCompletions {
async fn response_from_proto(
self,
message: proto::GetCompletionsResponse,
_: Handle<Project>,
buffer: Handle<Buffer>,
_: Model<Project>,
buffer: Model<Buffer>,
mut cx: AsyncAppContext,
) -> Result<Vec<Completion>> {
buffer
@ -1589,8 +1589,8 @@ impl LspCommand for GetCodeActions {
async fn response_from_lsp(
self,
actions: Option<lsp2::CodeActionResponse>,
_: Handle<Project>,
_: Handle<Buffer>,
_: Model<Project>,
_: Model<Buffer>,
server_id: LanguageServerId,
_: AsyncAppContext,
) -> Result<Vec<CodeAction>> {
@ -1623,8 +1623,8 @@ impl LspCommand for GetCodeActions {
async fn from_proto(
message: proto::GetCodeActions,
_: Handle<Project>,
buffer: Handle<Buffer>,
_: Model<Project>,
buffer: Model<Buffer>,
mut cx: AsyncAppContext,
) -> Result<Self> {
let start = message
@ -1663,8 +1663,8 @@ impl LspCommand for GetCodeActions {
async fn response_from_proto(
self,
message: proto::GetCodeActionsResponse,
_: Handle<Project>,
buffer: Handle<Buffer>,
_: Model<Project>,
buffer: Model<Buffer>,
mut cx: AsyncAppContext,
) -> Result<Vec<CodeAction>> {
buffer
@ -1726,8 +1726,8 @@ impl LspCommand for OnTypeFormatting {
async fn response_from_lsp(
self,
message: Option<Vec<lsp2::TextEdit>>,
project: Handle<Project>,
buffer: Handle<Buffer>,
project: Model<Project>,
buffer: Model<Buffer>,
server_id: LanguageServerId,
mut cx: AsyncAppContext,
) -> Result<Option<Transaction>> {
@ -1763,8 +1763,8 @@ impl LspCommand for OnTypeFormatting {
async fn from_proto(
message: proto::OnTypeFormatting,
_: Handle<Project>,
buffer: Handle<Buffer>,
_: Model<Project>,
buffer: Model<Buffer>,
mut cx: AsyncAppContext,
) -> Result<Self> {
let position = message
@ -1805,8 +1805,8 @@ impl LspCommand for OnTypeFormatting {
async fn response_from_proto(
self,
message: proto::OnTypeFormattingResponse,
_: Handle<Project>,
_: Handle<Buffer>,
_: Model<Project>,
_: Model<Buffer>,
_: AsyncAppContext,
) -> Result<Option<Transaction>> {
let Some(transaction) = message.transaction else {
@ -1825,7 +1825,7 @@ impl LspCommand for OnTypeFormatting {
impl InlayHints {
pub async fn lsp_to_project_hint(
lsp_hint: lsp2::InlayHint,
buffer_handle: &Handle<Buffer>,
buffer_handle: &Model<Buffer>,
server_id: LanguageServerId,
resolve_state: ResolveState,
force_no_type_left_padding: bool,
@ -2230,8 +2230,8 @@ impl LspCommand for InlayHints {
async fn response_from_lsp(
self,
message: Option<Vec<lsp2::InlayHint>>,
project: Handle<Project>,
buffer: Handle<Buffer>,
project: Model<Project>,
buffer: Model<Buffer>,
server_id: LanguageServerId,
mut cx: AsyncAppContext,
) -> anyhow::Result<Vec<InlayHint>> {
@ -2286,8 +2286,8 @@ impl LspCommand for InlayHints {
async fn from_proto(
message: proto::InlayHints,
_: Handle<Project>,
buffer: Handle<Buffer>,
_: Model<Project>,
buffer: Model<Buffer>,
mut cx: AsyncAppContext,
) -> Result<Self> {
let start = message
@ -2326,8 +2326,8 @@ impl LspCommand for InlayHints {
async fn response_from_proto(
self,
message: proto::InlayHintsResponse,
_: Handle<Project>,
buffer: Handle<Buffer>,
_: Model<Project>,
buffer: Model<Buffer>,
mut cx: AsyncAppContext,
) -> anyhow::Result<Vec<InlayHint>> {
buffer

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
use crate::Project;
use gpui2::{AnyWindowHandle, Context, Handle, ModelContext, WeakHandle};
use gpui2::{AnyWindowHandle, Context, Model, ModelContext, WeakHandle};
use settings2::Settings;
use std::path::{Path, PathBuf};
use terminal2::{
@ -20,7 +20,7 @@ impl Project {
working_directory: Option<PathBuf>,
window: AnyWindowHandle,
cx: &mut ModelContext<Self>,
) -> anyhow::Result<Handle<Terminal>> {
) -> anyhow::Result<Model<Terminal>> {
if self.is_remote() {
return Err(anyhow::anyhow!(
"creating terminals as a guest is not supported yet"
@ -40,7 +40,7 @@ impl Project {
|_, _| todo!("color_for_index"),
)
.map(|builder| {
let terminal_handle = cx.entity(|cx| builder.subscribe(cx));
let terminal_handle = cx.build_model(|cx| builder.subscribe(cx));
self.terminals
.local_handles
@ -108,7 +108,7 @@ impl Project {
fn activate_python_virtual_environment(
&mut self,
activate_script: Option<PathBuf>,
terminal_handle: &Handle<Terminal>,
terminal_handle: &Model<Terminal>,
cx: &mut ModelContext<Project>,
) {
if let Some(activate_script) = activate_script {

View file

@ -22,7 +22,7 @@ use futures::{
use fuzzy2::CharBag;
use git::{DOT_GIT, GITIGNORE};
use gpui2::{
AppContext, AsyncAppContext, Context, EventEmitter, Executor, Handle, ModelContext, Task,
AppContext, AsyncAppContext, Context, EventEmitter, Executor, Model, ModelContext, Task,
};
use language2::{
proto::{
@ -292,7 +292,7 @@ impl Worktree {
fs: Arc<dyn Fs>,
next_entry_id: Arc<AtomicUsize>,
cx: &mut AsyncAppContext,
) -> Result<Handle<Self>> {
) -> Result<Model<Self>> {
// After determining whether the root entry is a file or a directory, populate the
// snapshot's "root name", which will be used for the purpose of fuzzy matching.
let abs_path = path.into();
@ -301,7 +301,7 @@ impl Worktree {
.await
.context("failed to stat worktree path")?;
cx.entity(move |cx: &mut ModelContext<Worktree>| {
cx.build_model(move |cx: &mut ModelContext<Worktree>| {
let root_name = abs_path
.file_name()
.map_or(String::new(), |f| f.to_string_lossy().to_string());
@ -406,8 +406,8 @@ impl Worktree {
worktree: proto::WorktreeMetadata,
client: Arc<Client>,
cx: &mut AppContext,
) -> Handle<Self> {
cx.entity(|cx: &mut ModelContext<Self>| {
) -> Model<Self> {
cx.build_model(|cx: &mut ModelContext<Self>| {
let snapshot = Snapshot {
id: WorktreeId(worktree.id as usize),
abs_path: Arc::from(PathBuf::from(worktree.abs_path)),
@ -593,7 +593,7 @@ impl LocalWorktree {
id: u64,
path: &Path,
cx: &mut ModelContext<Worktree>,
) -> Task<Result<Handle<Buffer>>> {
) -> Task<Result<Model<Buffer>>> {
let path = Arc::from(path);
cx.spawn(move |this, mut cx| async move {
let (file, contents, diff_base) = this
@ -603,7 +603,7 @@ impl LocalWorktree {
.executor()
.spawn(async move { text::Buffer::new(0, id, contents) })
.await;
cx.entity(|_| Buffer::build(text_buffer, diff_base, Some(Arc::new(file))))
cx.build_model(|_| Buffer::build(text_buffer, diff_base, Some(Arc::new(file))))
})
}
@ -920,7 +920,7 @@ impl LocalWorktree {
pub fn save_buffer(
&self,
buffer_handle: Handle<Buffer>,
buffer_handle: Model<Buffer>,
path: Arc<Path>,
has_changed_file: bool,
cx: &mut ModelContext<Worktree>,
@ -1331,7 +1331,7 @@ impl RemoteWorktree {
pub fn save_buffer(
&self,
buffer_handle: Handle<Buffer>,
buffer_handle: Model<Buffer>,
cx: &mut ModelContext<Worktree>,
) -> Task<Result<()>> {
let buffer = buffer_handle.read(cx);
@ -2577,7 +2577,7 @@ impl fmt::Debug for Snapshot {
#[derive(Clone, PartialEq)]
pub struct File {
pub worktree: Handle<Worktree>,
pub worktree: Model<Worktree>,
pub path: Arc<Path>,
pub mtime: SystemTime,
pub(crate) entry_id: ProjectEntryId,
@ -2701,7 +2701,7 @@ impl language2::LocalFile for File {
}
impl File {
pub fn for_entry(entry: Entry, worktree: Handle<Worktree>) -> Arc<Self> {
pub fn for_entry(entry: Entry, worktree: Model<Worktree>) -> Arc<Self> {
Arc::new(Self {
worktree,
path: entry.path.clone(),
@ -2714,7 +2714,7 @@ impl File {
pub fn from_proto(
proto: rpc2::proto::File,
worktree: Handle<Worktree>,
worktree: Model<Worktree>,
cx: &AppContext,
) -> Result<Self> {
let worktree_id = worktree

View file

@ -14,7 +14,7 @@ impl KitchenSinkStory {
pub fn view(cx: &mut AppContext) -> View<Self> {
{
let state = cx.entity(|cx| Self::new());
let state = cx.build_model(|cx| Self::new());
let render = Self::render;
View::for_handle(state, render)
}

View file

@ -23,7 +23,7 @@ impl BufferSearch {
pub fn view(cx: &mut AppContext) -> View<Self> {
{
let state = cx.entity(|cx| Self::new());
let state = cx.build_model(|cx| Self::new());
let render = Self::render;
View::for_handle(state, render)
}

View file

@ -44,7 +44,7 @@ impl EditorPane {
pub fn view(cx: &mut AppContext) -> View<Self> {
{
let state = cx.entity(|cx| hello_world_rust_editor_with_status_example(cx));
let state = cx.build_model(|cx| hello_world_rust_editor_with_status_example(cx));
let render = Self::render;
View::for_handle(state, render)
}

View file

@ -82,7 +82,7 @@ impl TitleBar {
pub fn view(cx: &mut AppContext, livestream: Option<Livestream>) -> View<Self> {
{
let state = cx.entity(|cx| Self::new(cx).set_livestream(livestream));
let state = cx.build_model(|cx| Self::new(cx).set_livestream(livestream));
let render = Self::render;
View::for_handle(state, render)
}
@ -198,7 +198,7 @@ mod stories {
impl TitleBarStory {
pub fn view(cx: &mut AppContext) -> View<Self> {
{
let state = cx.entity(|cx| Self {
let state = cx.build_model(|cx| Self {
title_bar: TitleBar::view(cx, None),
});
let render = Self::render;

View file

@ -3,12 +3,13 @@ use std::sync::Arc;
use chrono::DateTime;
use gpui2::{px, relative, rems, AppContext, Context, Size, View};
use crate::{static_livestream, user_settings_mut, v_stack, AssistantPanel, Button, ChatMessage,
ChatPanel, CollabPanel, EditorPane, FakeSettings, Label, LanguageSelector, Pane, PaneGroup,
Panel, PanelAllowedSides, PanelSide, ProjectPanel, SettingValue, SplitDirection, StatusBar,
Terminal, TitleBar, Toast, ToastOrigin,
};
use crate::{prelude::*, NotificationsPanel};
use crate::{
static_livestream, user_settings_mut, v_stack, AssistantPanel, Button, ChatMessage, ChatPanel,
CollabPanel, EditorPane, FakeSettings, Label, LanguageSelector, Pane, PaneGroup, Panel,
PanelAllowedSides, PanelSide, ProjectPanel, SettingValue, SplitDirection, StatusBar, Terminal,
TitleBar, Toast, ToastOrigin,
};
#[derive(Clone)]
pub struct Gpui2UiDebug {
@ -171,7 +172,7 @@ impl Workspace {
pub fn view(cx: &mut AppContext) -> View<Self> {
{
let state = cx.entity(|cx| Self::new(cx));
let state = cx.build_model(|cx| Self::new(cx));
let render = Self::render;
View::for_handle(state, render)
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,993 @@
use crate::{AppState, FollowerState, Pane, Workspace};
use anyhow::{anyhow, Result};
use call2::ActiveCall;
use collections::HashMap;
use gpui2::{size, AnyElement, AnyView, Bounds, Handle, Pixels, Point, View, ViewContext};
use project2::Project;
use serde::Deserialize;
use std::{cell::RefCell, rc::Rc, sync::Arc};
use theme2::Theme;
const HANDLE_HITBOX_SIZE: f32 = 4.0;
const HORIZONTAL_MIN_SIZE: f32 = 80.;
const VERTICAL_MIN_SIZE: f32 = 100.;
pub enum Axis {
Vertical,
Horizontal,
}
#[derive(Clone, Debug, PartialEq)]
pub struct PaneGroup {
pub(crate) root: Member,
}
impl PaneGroup {
pub(crate) fn with_root(root: Member) -> Self {
Self { root }
}
pub fn new(pane: View<Pane>) -> Self {
Self {
root: Member::Pane(pane),
}
}
pub fn split(
&mut self,
old_pane: &View<Pane>,
new_pane: &View<Pane>,
direction: SplitDirection,
) -> Result<()> {
match &mut self.root {
Member::Pane(pane) => {
if pane == old_pane {
self.root = Member::new_axis(old_pane.clone(), new_pane.clone(), direction);
Ok(())
} else {
Err(anyhow!("Pane not found"))
}
}
Member::Axis(axis) => axis.split(old_pane, new_pane, direction),
}
}
pub fn bounding_box_for_pane(&self, pane: &View<Pane>) -> Option<Bounds<Pixels>> {
match &self.root {
Member::Pane(_) => None,
Member::Axis(axis) => axis.bounding_box_for_pane(pane),
}
}
pub fn pane_at_pixel_position(&self, coordinate: Point<Pixels>) -> Option<&View<Pane>> {
match &self.root {
Member::Pane(pane) => Some(pane),
Member::Axis(axis) => axis.pane_at_pixel_position(coordinate),
}
}
/// Returns:
/// - Ok(true) if it found and removed a pane
/// - Ok(false) if it found but did not remove the pane
/// - Err(_) if it did not find the pane
pub fn remove(&mut self, pane: &View<Pane>) -> Result<bool> {
match &mut self.root {
Member::Pane(_) => Ok(false),
Member::Axis(axis) => {
if let Some(last_pane) = axis.remove(pane)? {
self.root = last_pane;
}
Ok(true)
}
}
}
pub fn swap(&mut self, from: &View<Pane>, to: &View<Pane>) {
match &mut self.root {
Member::Pane(_) => {}
Member::Axis(axis) => axis.swap(from, to),
};
}
pub(crate) fn render(
&self,
project: &Handle<Project>,
theme: &Theme,
follower_states: &HashMap<View<Pane>, FollowerState>,
active_call: Option<&Handle<ActiveCall>>,
active_pane: &View<Pane>,
zoomed: Option<&AnyView>,
app_state: &Arc<AppState>,
cx: &mut ViewContext<Workspace>,
) -> AnyElement<Workspace> {
self.root.render(
project,
0,
theme,
follower_states,
active_call,
active_pane,
zoomed,
app_state,
cx,
)
}
pub(crate) fn panes(&self) -> Vec<&View<Pane>> {
let mut panes = Vec::new();
self.root.collect_panes(&mut panes);
panes
}
}
#[derive(Clone, Debug, PartialEq)]
pub(crate) enum Member {
Axis(PaneAxis),
Pane(View<Pane>),
}
impl Member {
fn new_axis(old_pane: View<Pane>, new_pane: View<Pane>, direction: SplitDirection) -> Self {
use Axis::*;
use SplitDirection::*;
let axis = match direction {
Up | Down => Vertical,
Left | Right => Horizontal,
};
let members = match direction {
Up | Left => vec![Member::Pane(new_pane), Member::Pane(old_pane)],
Down | Right => vec![Member::Pane(old_pane), Member::Pane(new_pane)],
};
Member::Axis(PaneAxis::new(axis, members))
}
fn contains(&self, needle: &View<Pane>) -> bool {
match self {
Member::Axis(axis) => axis.members.iter().any(|member| member.contains(needle)),
Member::Pane(pane) => pane == needle,
}
}
pub fn render(
&self,
project: &Handle<Project>,
basis: usize,
theme: &Theme,
follower_states: &HashMap<View<Pane>, FollowerState>,
active_call: Option<&Handle<ActiveCall>>,
active_pane: &View<Pane>,
zoomed: Option<&AnyView>,
app_state: &Arc<AppState>,
cx: &mut ViewContext<Workspace>,
) -> AnyElement<Workspace> {
todo!()
// enum FollowIntoExternalProject {}
// match self {
// Member::Pane(pane) => {
// let pane_element = if Some(&**pane) == zoomed {
// Empty::new().into_any()
// } else {
// ChildView::new(pane, cx).into_any()
// };
// let leader = follower_states.get(pane).and_then(|state| {
// let room = active_call?.read(cx).room()?.read(cx);
// room.remote_participant_for_peer_id(state.leader_id)
// });
// let mut leader_border = Border::default();
// let mut leader_status_box = None;
// if let Some(leader) = &leader {
// let leader_color = theme
// .editor
// .selection_style_for_room_participant(leader.participant_index.0)
// .cursor;
// leader_border = Border::all(theme.workspace.leader_border_width, leader_color);
// leader_border
// .color
// .fade_out(1. - theme.workspace.leader_border_opacity);
// leader_border.overlay = true;
// leader_status_box = match leader.location {
// ParticipantLocation::SharedProject {
// project_id: leader_project_id,
// } => {
// if Some(leader_project_id) == project.read(cx).remote_id() {
// None
// } else {
// let leader_user = leader.user.clone();
// let leader_user_id = leader.user.id;
// Some(
// MouseEventHandler::new::<FollowIntoExternalProject, _>(
// pane.id(),
// cx,
// |_, _| {
// Label::new(
// format!(
// "Follow {} to their active project",
// leader_user.github_login,
// ),
// theme
// .workspace
// .external_location_message
// .text
// .clone(),
// )
// .contained()
// .with_style(
// theme.workspace.external_location_message.container,
// )
// },
// )
// .with_cursor_style(CursorStyle::PointingHand)
// .on_click(MouseButton::Left, move |_, this, cx| {
// crate::join_remote_project(
// leader_project_id,
// leader_user_id,
// this.app_state().clone(),
// cx,
// )
// .detach_and_log_err(cx);
// })
// .aligned()
// .bottom()
// .right()
// .into_any(),
// )
// }
// }
// ParticipantLocation::UnsharedProject => Some(
// Label::new(
// format!(
// "{} is viewing an unshared Zed project",
// leader.user.github_login
// ),
// theme.workspace.external_location_message.text.clone(),
// )
// .contained()
// .with_style(theme.workspace.external_location_message.container)
// .aligned()
// .bottom()
// .right()
// .into_any(),
// ),
// ParticipantLocation::External => Some(
// Label::new(
// format!(
// "{} is viewing a window outside of Zed",
// leader.user.github_login
// ),
// theme.workspace.external_location_message.text.clone(),
// )
// .contained()
// .with_style(theme.workspace.external_location_message.container)
// .aligned()
// .bottom()
// .right()
// .into_any(),
// ),
// };
// }
// Stack::new()
// .with_child(pane_element.contained().with_border(leader_border))
// .with_children(leader_status_box)
// .into_any()
// }
// Member::Axis(axis) => axis.render(
// project,
// basis + 1,
// theme,
// follower_states,
// active_call,
// active_pane,
// zoomed,
// app_state,
// cx,
// ),
// }
}
fn collect_panes<'a>(&'a self, panes: &mut Vec<&'a View<Pane>>) {
match self {
Member::Axis(axis) => {
for member in &axis.members {
member.collect_panes(panes);
}
}
Member::Pane(pane) => panes.push(pane),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub(crate) struct PaneAxis {
pub axis: Axis,
pub members: Vec<Member>,
pub flexes: Rc<RefCell<Vec<f32>>>,
pub bounding_boxes: Rc<RefCell<Vec<Option<Bounds<Pixels>>>>>,
}
impl PaneAxis {
pub fn new(axis: Axis, members: Vec<Member>) -> Self {
let flexes = Rc::new(RefCell::new(vec![1.; members.len()]));
let bounding_boxes = Rc::new(RefCell::new(vec![None; members.len()]));
Self {
axis,
members,
flexes,
bounding_boxes,
}
}
pub fn load(axis: Axis, members: Vec<Member>, flexes: Option<Vec<f32>>) -> Self {
let flexes = flexes.unwrap_or_else(|| vec![1.; members.len()]);
debug_assert!(members.len() == flexes.len());
let flexes = Rc::new(RefCell::new(flexes));
let bounding_boxes = Rc::new(RefCell::new(vec![None; members.len()]));
Self {
axis,
members,
flexes,
bounding_boxes,
}
}
fn split(
&mut self,
old_pane: &View<Pane>,
new_pane: &View<Pane>,
direction: SplitDirection,
) -> Result<()> {
for (mut idx, member) in self.members.iter_mut().enumerate() {
match member {
Member::Axis(axis) => {
if axis.split(old_pane, new_pane, direction).is_ok() {
return Ok(());
}
}
Member::Pane(pane) => {
if pane == old_pane {
if direction.axis() == self.axis {
if direction.increasing() {
idx += 1;
}
self.members.insert(idx, Member::Pane(new_pane.clone()));
*self.flexes.borrow_mut() = vec![1.; self.members.len()];
} else {
*member =
Member::new_axis(old_pane.clone(), new_pane.clone(), direction);
}
return Ok(());
}
}
}
}
Err(anyhow!("Pane not found"))
}
fn remove(&mut self, pane_to_remove: &View<Pane>) -> Result<Option<Member>> {
let mut found_pane = false;
let mut remove_member = None;
for (idx, member) in self.members.iter_mut().enumerate() {
match member {
Member::Axis(axis) => {
if let Ok(last_pane) = axis.remove(pane_to_remove) {
if let Some(last_pane) = last_pane {
*member = last_pane;
}
found_pane = true;
break;
}
}
Member::Pane(pane) => {
if pane == pane_to_remove {
found_pane = true;
remove_member = Some(idx);
break;
}
}
}
}
if found_pane {
if let Some(idx) = remove_member {
self.members.remove(idx);
*self.flexes.borrow_mut() = vec![1.; self.members.len()];
}
if self.members.len() == 1 {
let result = self.members.pop();
*self.flexes.borrow_mut() = vec![1.; self.members.len()];
Ok(result)
} else {
Ok(None)
}
} else {
Err(anyhow!("Pane not found"))
}
}
fn swap(&mut self, from: &View<Pane>, to: &View<Pane>) {
for member in self.members.iter_mut() {
match member {
Member::Axis(axis) => axis.swap(from, to),
Member::Pane(pane) => {
if pane == from {
*member = Member::Pane(to.clone());
} else if pane == to {
*member = Member::Pane(from.clone())
}
}
}
}
}
fn bounding_box_for_pane(&self, pane: &View<Pane>) -> Option<Bounds<Pixels>> {
debug_assert!(self.members.len() == self.bounding_boxes.borrow().len());
for (idx, member) in self.members.iter().enumerate() {
match member {
Member::Pane(found) => {
if pane == found {
return self.bounding_boxes.borrow()[idx];
}
}
Member::Axis(axis) => {
if let Some(rect) = axis.bounding_box_for_pane(pane) {
return Some(rect);
}
}
}
}
None
}
fn pane_at_pixel_position(&self, coordinate: Point<Pixels>) -> Option<&View<Pane>> {
debug_assert!(self.members.len() == self.bounding_boxes.borrow().len());
let bounding_boxes = self.bounding_boxes.borrow();
for (idx, member) in self.members.iter().enumerate() {
if let Some(coordinates) = bounding_boxes[idx] {
if coordinates.contains_point(&coordinate) {
return match member {
Member::Pane(found) => Some(found),
Member::Axis(axis) => axis.pane_at_pixel_position(coordinate),
};
}
}
}
None
}
fn render(
&self,
project: &Handle<Project>,
basis: usize,
theme: &Theme,
follower_states: &HashMap<View<Pane>, FollowerState>,
active_call: Option<&Handle<ActiveCall>>,
active_pane: &View<Pane>,
zoomed: Option<&AnyView>,
app_state: &Arc<AppState>,
cx: &mut ViewContext<Workspace>,
) -> AnyElement<Workspace> {
debug_assert!(self.members.len() == self.flexes.borrow().len());
todo!()
// let mut pane_axis = PaneAxisElement::new(
// self.axis,
// basis,
// self.flexes.clone(),
// self.bounding_boxes.clone(),
// );
// let mut active_pane_ix = None;
// let mut members = self.members.iter().enumerate().peekable();
// while let Some((ix, member)) = members.next() {
// let last = members.peek().is_none();
// if member.contains(active_pane) {
// active_pane_ix = Some(ix);
// }
// let mut member = member.render(
// project,
// (basis + ix) * 10,
// theme,
// follower_states,
// active_call,
// active_pane,
// zoomed,
// app_state,
// cx,
// );
// if !last {
// let mut border = theme.workspace.pane_divider;
// border.left = false;
// border.right = false;
// border.top = false;
// border.bottom = false;
// match self.axis {
// Axis::Vertical => border.bottom = true,
// Axis::Horizontal => border.right = true,
// }
// member = member.contained().with_border(border).into_any();
// }
// pane_axis = pane_axis.with_child(member.into_any());
// }
// pane_axis.set_active_pane(active_pane_ix);
// pane_axis.into_any()
}
}
#[derive(Clone, Copy, Debug, Deserialize, PartialEq)]
pub enum SplitDirection {
Up,
Down,
Left,
Right,
}
impl SplitDirection {
pub fn all() -> [Self; 4] {
[Self::Up, Self::Down, Self::Left, Self::Right]
}
pub fn edge(&self, rect: Bounds<Pixels>) -> f32 {
match self {
Self::Up => rect.min_y(),
Self::Down => rect.max_y(),
Self::Left => rect.min_x(),
Self::Right => rect.max_x(),
}
}
pub fn along_edge(&self, bounds: Bounds<Pixels>, length: Pixels) -> Bounds<Pixels> {
match self {
Self::Up => Bounds {
origin: bounds.origin(),
size: size(bounds.width(), length),
},
Self::Down => Bounds {
origin: size(bounds.min_x(), bounds.max_y() - length),
size: size(bounds.width(), length),
},
Self::Left => Bounds {
origin: bounds.origin(),
size: size(length, bounds.height()),
},
Self::Right => Bounds {
origin: size(bounds.max_x() - length, bounds.min_y()),
size: size(length, bounds.height()),
},
}
}
pub fn axis(&self) -> Axis {
match self {
Self::Up | Self::Down => Axis::Vertical,
Self::Left | Self::Right => Axis::Horizontal,
}
}
pub fn increasing(&self) -> bool {
match self {
Self::Left | Self::Up => false,
Self::Down | Self::Right => true,
}
}
}
// mod element {
// // use std::{cell::RefCell, iter::from_fn, ops::Range, rc::Rc};
// // use gpui::{
// // geometry::{
// // rect::Bounds<Pixels>,
// // vector::{vec2f, Vector2F},
// // },
// // json::{self, ToJson},
// // platform::{CursorStyle, MouseButton},
// // scene::MouseDrag,
// // AnyElement, Axis, CursorRegion, Element, EventContext, MouseRegion, Bounds<Pixels>Ext,
// // SizeConstraint, Vector2FExt, ViewContext,
// // };
// use crate::{
// pane_group::{HANDLE_HITBOX_SIZE, HORIZONTAL_MIN_SIZE, VERTICAL_MIN_SIZE},
// Workspace, WorkspaceSettings,
// };
// pub struct PaneAxisElement {
// axis: Axis,
// basis: usize,
// active_pane_ix: Option<usize>,
// flexes: Rc<RefCell<Vec<f32>>>,
// children: Vec<AnyElement<Workspace>>,
// bounding_boxes: Rc<RefCell<Vec<Option<Bounds<Pixels>>>>>,
// }
// impl PaneAxisElement {
// pub fn new(
// axis: Axis,
// basis: usize,
// flexes: Rc<RefCell<Vec<f32>>>,
// bounding_boxes: Rc<RefCell<Vec<Option<Bounds<Pixels>>>>>,
// ) -> Self {
// Self {
// axis,
// basis,
// flexes,
// bounding_boxes,
// active_pane_ix: None,
// children: Default::default(),
// }
// }
// pub fn set_active_pane(&mut self, active_pane_ix: Option<usize>) {
// self.active_pane_ix = active_pane_ix;
// }
// fn layout_children(
// &mut self,
// active_pane_magnification: f32,
// constraint: SizeConstraint,
// remaining_space: &mut f32,
// remaining_flex: &mut f32,
// cross_axis_max: &mut f32,
// view: &mut Workspace,
// cx: &mut ViewContext<Workspace>,
// ) {
// let flexes = self.flexes.borrow();
// let cross_axis = self.axis.invert();
// for (ix, child) in self.children.iter_mut().enumerate() {
// let flex = if active_pane_magnification != 1. {
// if let Some(active_pane_ix) = self.active_pane_ix {
// if ix == active_pane_ix {
// active_pane_magnification
// } else {
// 1.
// }
// } else {
// 1.
// }
// } else {
// flexes[ix]
// };
// let child_size = if *remaining_flex == 0.0 {
// *remaining_space
// } else {
// let space_per_flex = *remaining_space / *remaining_flex;
// space_per_flex * flex
// };
// let child_constraint = match self.axis {
// Axis::Horizontal => SizeConstraint::new(
// vec2f(child_size, constraint.min.y()),
// vec2f(child_size, constraint.max.y()),
// ),
// Axis::Vertical => SizeConstraint::new(
// vec2f(constraint.min.x(), child_size),
// vec2f(constraint.max.x(), child_size),
// ),
// };
// let child_size = child.layout(child_constraint, view, cx);
// *remaining_space -= child_size.along(self.axis);
// *remaining_flex -= flex;
// *cross_axis_max = cross_axis_max.max(child_size.along(cross_axis));
// }
// }
// fn handle_resize(
// flexes: Rc<RefCell<Vec<f32>>>,
// axis: Axis,
// preceding_ix: usize,
// child_start: Vector2F,
// drag_bounds: Bounds<Pixels>,
// ) -> impl Fn(MouseDrag, &mut Workspace, &mut EventContext<Workspace>) {
// let size = move |ix, flexes: &[f32]| {
// drag_bounds.length_along(axis) * (flexes[ix] / flexes.len() as f32)
// };
// move |drag, workspace: &mut Workspace, cx| {
// if drag.end {
// // TODO: Clear cascading resize state
// return;
// }
// let min_size = match axis {
// Axis::Horizontal => HORIZONTAL_MIN_SIZE,
// Axis::Vertical => VERTICAL_MIN_SIZE,
// };
// let mut flexes = flexes.borrow_mut();
// // Don't allow resizing to less than the minimum size, if elements are already too small
// if min_size - 1. > size(preceding_ix, flexes.as_slice()) {
// return;
// }
// let mut proposed_current_pixel_change = (drag.position - child_start).along(axis)
// - size(preceding_ix, flexes.as_slice());
// let flex_changes = |pixel_dx, target_ix, next: isize, flexes: &[f32]| {
// let flex_change = pixel_dx / drag_bounds.length_along(axis);
// let current_target_flex = flexes[target_ix] + flex_change;
// let next_target_flex =
// flexes[(target_ix as isize + next) as usize] - flex_change;
// (current_target_flex, next_target_flex)
// };
// let mut successors = from_fn({
// let forward = proposed_current_pixel_change > 0.;
// let mut ix_offset = 0;
// let len = flexes.len();
// move || {
// let result = if forward {
// (preceding_ix + 1 + ix_offset < len).then(|| preceding_ix + ix_offset)
// } else {
// (preceding_ix as isize - ix_offset as isize >= 0)
// .then(|| preceding_ix - ix_offset)
// };
// ix_offset += 1;
// result
// }
// });
// while proposed_current_pixel_change.abs() > 0. {
// let Some(current_ix) = successors.next() else {
// break;
// };
// let next_target_size = f32::max(
// size(current_ix + 1, flexes.as_slice()) - proposed_current_pixel_change,
// min_size,
// );
// let current_target_size = f32::max(
// size(current_ix, flexes.as_slice())
// + size(current_ix + 1, flexes.as_slice())
// - next_target_size,
// min_size,
// );
// let current_pixel_change =
// current_target_size - size(current_ix, flexes.as_slice());
// let (current_target_flex, next_target_flex) =
// flex_changes(current_pixel_change, current_ix, 1, flexes.as_slice());
// flexes[current_ix] = current_target_flex;
// flexes[current_ix + 1] = next_target_flex;
// proposed_current_pixel_change -= current_pixel_change;
// }
// workspace.schedule_serialize(cx);
// cx.notify();
// }
// }
// }
// impl Extend<AnyElement<Workspace>> for PaneAxisElement {
// fn extend<T: IntoIterator<Item = AnyElement<Workspace>>>(&mut self, children: T) {
// self.children.extend(children);
// }
// }
// impl Element<Workspace> for PaneAxisElement {
// type LayoutState = f32;
// type PaintState = ();
// fn layout(
// &mut self,
// constraint: SizeConstraint,
// view: &mut Workspace,
// cx: &mut ViewContext<Workspace>,
// ) -> (Vector2F, Self::LayoutState) {
// debug_assert!(self.children.len() == self.flexes.borrow().len());
// let active_pane_magnification =
// settings::get::<WorkspaceSettings>(cx).active_pane_magnification;
// let mut remaining_flex = 0.;
// if active_pane_magnification != 1. {
// let active_pane_flex = self
// .active_pane_ix
// .map(|_| active_pane_magnification)
// .unwrap_or(1.);
// remaining_flex += self.children.len() as f32 - 1. + active_pane_flex;
// } else {
// for flex in self.flexes.borrow().iter() {
// remaining_flex += flex;
// }
// }
// let mut cross_axis_max: f32 = 0.0;
// let mut remaining_space = constraint.max_along(self.axis);
// if remaining_space.is_infinite() {
// panic!("flex contains flexible children but has an infinite constraint along the flex axis");
// }
// self.layout_children(
// active_pane_magnification,
// constraint,
// &mut remaining_space,
// &mut remaining_flex,
// &mut cross_axis_max,
// view,
// cx,
// );
// let mut size = match self.axis {
// Axis::Horizontal => vec2f(constraint.max.x() - remaining_space, cross_axis_max),
// Axis::Vertical => vec2f(cross_axis_max, constraint.max.y() - remaining_space),
// };
// if constraint.min.x().is_finite() {
// size.set_x(size.x().max(constraint.min.x()));
// }
// if constraint.min.y().is_finite() {
// size.set_y(size.y().max(constraint.min.y()));
// }
// if size.x() > constraint.max.x() {
// size.set_x(constraint.max.x());
// }
// if size.y() > constraint.max.y() {
// size.set_y(constraint.max.y());
// }
// (size, remaining_space)
// }
// fn paint(
// &mut self,
// bounds: Bounds<Pixels>,
// visible_bounds: Bounds<Pixels>,
// remaining_space: &mut Self::LayoutState,
// view: &mut Workspace,
// cx: &mut ViewContext<Workspace>,
// ) -> Self::PaintState {
// let can_resize = settings::get::<WorkspaceSettings>(cx).active_pane_magnification == 1.;
// let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
// let overflowing = *remaining_space < 0.;
// if overflowing {
// cx.scene().push_layer(Some(visible_bounds));
// }
// let mut child_origin = bounds.origin();
// let mut bounding_boxes = self.bounding_boxes.borrow_mut();
// bounding_boxes.clear();
// let mut children_iter = self.children.iter_mut().enumerate().peekable();
// while let Some((ix, child)) = children_iter.next() {
// let child_start = child_origin.clone();
// child.paint(child_origin, visible_bounds, view, cx);
// bounding_boxes.push(Some(Bounds<Pixels>::new(child_origin, child.size())));
// match self.axis {
// Axis::Horizontal => child_origin += vec2f(child.size().x(), 0.0),
// Axis::Vertical => child_origin += vec2f(0.0, child.size().y()),
// }
// if can_resize && children_iter.peek().is_some() {
// cx.scene().push_stacking_context(None, None);
// let handle_origin = match self.axis {
// Axis::Horizontal => child_origin - vec2f(HANDLE_HITBOX_SIZE / 2., 0.0),
// Axis::Vertical => child_origin - vec2f(0.0, HANDLE_HITBOX_SIZE / 2.),
// };
// let handle_bounds = match self.axis {
// Axis::Horizontal => Bounds<Pixels>::new(
// handle_origin,
// vec2f(HANDLE_HITBOX_SIZE, visible_bounds.height()),
// ),
// Axis::Vertical => Bounds<Pixels>::new(
// handle_origin,
// vec2f(visible_bounds.width(), HANDLE_HITBOX_SIZE),
// ),
// };
// let style = match self.axis {
// Axis::Horizontal => CursorStyle::ResizeLeftRight,
// Axis::Vertical => CursorStyle::ResizeUpDown,
// };
// cx.scene().push_cursor_region(CursorRegion {
// bounds: handle_bounds,
// style,
// });
// enum ResizeHandle {}
// let mut mouse_region = MouseRegion::new::<ResizeHandle>(
// cx.view_id(),
// self.basis + ix,
// handle_bounds,
// );
// mouse_region = mouse_region
// .on_drag(
// MouseButton::Left,
// Self::handle_resize(
// self.flexes.clone(),
// self.axis,
// ix,
// child_start,
// visible_bounds.clone(),
// ),
// )
// .on_click(MouseButton::Left, {
// let flexes = self.flexes.clone();
// move |e, v: &mut Workspace, cx| {
// if e.click_count >= 2 {
// let mut borrow = flexes.borrow_mut();
// *borrow = vec![1.; borrow.len()];
// v.schedule_serialize(cx);
// cx.notify();
// }
// }
// });
// cx.scene().push_mouse_region(mouse_region);
// cx.scene().pop_stacking_context();
// }
// }
// if overflowing {
// cx.scene().pop_layer();
// }
// }
// fn rect_for_text_range(
// &self,
// range_utf16: Range<usize>,
// _: Bounds<Pixels>,
// _: Bounds<Pixels>,
// _: &Self::LayoutState,
// _: &Self::PaintState,
// view: &Workspace,
// cx: &ViewContext<Workspace>,
// ) -> Option<Bounds<Pixels>> {
// self.children
// .iter()
// .find_map(|child| child.rect_for_text_range(range_utf16.clone(), view, cx))
// }
// fn debug(
// &self,
// bounds: Bounds<Pixels>,
// _: &Self::LayoutState,
// _: &Self::PaintState,
// view: &Workspace,
// cx: &ViewContext<Workspace>,
// ) -> json::Value {
// serde_json::json!({
// "type": "PaneAxis",
// "bounds": bounds.to_json(),
// "axis": self.axis.to_json(),
// "flexes": *self.flexes.borrow(),
// "children": self.children.iter().map(|child| child.debug(view, cx)).collect::<Vec<json::Value>>()
// })
// }
// }
// }

View file

@ -0,0 +1,340 @@
use crate::{
item::ItemHandle, Axis, ItemDeserializers, Member, Pane, PaneAxis, Workspace, WorkspaceId,
};
use anyhow::{Context, Result};
use async_recursion::async_recursion;
use db2::sqlez::{
bindable::{Bind, Column, StaticColumnCount},
statement::Statement,
};
use gpui2::{AsyncAppContext, Handle, Task, View, WeakView, WindowBounds};
use project2::Project;
use std::{
path::{Path, PathBuf},
sync::Arc,
};
use util::ResultExt;
use uuid::Uuid;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct WorkspaceLocation(Arc<Vec<PathBuf>>);
impl WorkspaceLocation {
pub fn paths(&self) -> Arc<Vec<PathBuf>> {
self.0.clone()
}
}
impl<P: AsRef<Path>, T: IntoIterator<Item = P>> From<T> for WorkspaceLocation {
fn from(iterator: T) -> Self {
let mut roots = iterator
.into_iter()
.map(|p| p.as_ref().to_path_buf())
.collect::<Vec<_>>();
roots.sort();
Self(Arc::new(roots))
}
}
impl StaticColumnCount for WorkspaceLocation {}
impl Bind for &WorkspaceLocation {
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
bincode::serialize(&self.0)
.expect("Bincode serialization of paths should not fail")
.bind(statement, start_index)
}
}
impl Column for WorkspaceLocation {
fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
let blob = statement.column_blob(start_index)?;
Ok((
WorkspaceLocation(bincode::deserialize(blob).context("Bincode failed")?),
start_index + 1,
))
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct SerializedWorkspace {
pub id: WorkspaceId,
pub location: WorkspaceLocation,
pub center_group: SerializedPaneGroup,
pub bounds: Option<WindowBounds>,
pub display: Option<Uuid>,
pub docks: DockStructure,
}
#[derive(Debug, PartialEq, Clone, Default)]
pub struct DockStructure {
pub(crate) left: DockData,
pub(crate) right: DockData,
pub(crate) bottom: DockData,
}
impl Column for DockStructure {
fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
let (left, next_index) = DockData::column(statement, start_index)?;
let (right, next_index) = DockData::column(statement, next_index)?;
let (bottom, next_index) = DockData::column(statement, next_index)?;
Ok((
DockStructure {
left,
right,
bottom,
},
next_index,
))
}
}
impl Bind for DockStructure {
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
let next_index = statement.bind(&self.left, start_index)?;
let next_index = statement.bind(&self.right, next_index)?;
statement.bind(&self.bottom, next_index)
}
}
#[derive(Debug, PartialEq, Clone, Default)]
pub struct DockData {
pub(crate) visible: bool,
pub(crate) active_panel: Option<String>,
pub(crate) zoom: bool,
}
impl Column for DockData {
fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
let (visible, next_index) = Option::<bool>::column(statement, start_index)?;
let (active_panel, next_index) = Option::<String>::column(statement, next_index)?;
let (zoom, next_index) = Option::<bool>::column(statement, next_index)?;
Ok((
DockData {
visible: visible.unwrap_or(false),
active_panel,
zoom: zoom.unwrap_or(false),
},
next_index,
))
}
}
impl Bind for DockData {
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
let next_index = statement.bind(&self.visible, start_index)?;
let next_index = statement.bind(&self.active_panel, next_index)?;
statement.bind(&self.zoom, next_index)
}
}
#[derive(Debug, PartialEq, Clone)]
pub enum SerializedPaneGroup {
Group {
axis: Axis,
flexes: Option<Vec<f32>>,
children: Vec<SerializedPaneGroup>,
},
Pane(SerializedPane),
}
#[cfg(test)]
impl Default for SerializedPaneGroup {
fn default() -> Self {
Self::Pane(SerializedPane {
children: vec![SerializedItem::default()],
active: false,
})
}
}
impl SerializedPaneGroup {
#[async_recursion(?Send)]
pub(crate) async fn deserialize(
self,
project: &Handle<Project>,
workspace_id: WorkspaceId,
workspace: &WeakView<Workspace>,
cx: &mut AsyncAppContext,
) -> Option<(Member, Option<View<Pane>>, Vec<Option<Box<dyn ItemHandle>>>)> {
match self {
SerializedPaneGroup::Group {
axis,
children,
flexes,
} => {
let mut current_active_pane = None;
let mut members = Vec::new();
let mut items = Vec::new();
for child in children {
if let Some((new_member, active_pane, new_items)) = child
.deserialize(project, workspace_id, workspace, cx)
.await
{
members.push(new_member);
items.extend(new_items);
current_active_pane = current_active_pane.or(active_pane);
}
}
if members.is_empty() {
return None;
}
if members.len() == 1 {
return Some((members.remove(0), current_active_pane, items));
}
Some((
Member::Axis(PaneAxis::load(axis, members, flexes)),
current_active_pane,
items,
))
}
SerializedPaneGroup::Pane(serialized_pane) => {
let pane = workspace
.update(cx, |workspace, cx| workspace.add_pane(cx).downgrade())
.log_err()?;
let active = serialized_pane.active;
let new_items = serialized_pane
.deserialize_to(project, &pane, workspace_id, workspace, cx)
.await
.log_err()?;
if pane
.read_with(cx, |pane, _| pane.items_len() != 0)
.log_err()?
{
let pane = pane.upgrade()?;
Some((Member::Pane(pane.clone()), active.then(|| pane), new_items))
} else {
let pane = pane.upgrade()?;
workspace
.update(cx, |workspace, cx| workspace.force_remove_pane(&pane, cx))
.log_err()?;
None
}
}
}
}
}
#[derive(Debug, PartialEq, Eq, Default, Clone)]
pub struct SerializedPane {
pub(crate) active: bool,
pub(crate) children: Vec<SerializedItem>,
}
impl SerializedPane {
pub fn new(children: Vec<SerializedItem>, active: bool) -> Self {
SerializedPane { children, active }
}
pub async fn deserialize_to(
&self,
project: &Handle<Project>,
pane: &WeakView<Pane>,
workspace_id: WorkspaceId,
workspace: &WeakView<Workspace>,
cx: &mut AsyncAppContext,
) -> Result<Vec<Option<Box<dyn ItemHandle>>>> {
let mut items = Vec::new();
let mut active_item_index = None;
for (index, item) in self.children.iter().enumerate() {
let project = project.clone();
let item_handle = pane
.update(cx, |_, cx| {
if let Some(deserializer) = cx.global::<ItemDeserializers>().get(&item.kind) {
deserializer(project, workspace.clone(), workspace_id, item.item_id, cx)
} else {
Task::ready(Err(anyhow::anyhow!(
"Deserializer does not exist for item kind: {}",
item.kind
)))
}
})?
.await
.log_err();
items.push(item_handle.clone());
if let Some(item_handle) = item_handle {
pane.update(cx, |pane, cx| {
pane.add_item(item_handle.clone(), true, true, None, cx);
})?;
}
if item.active {
active_item_index = Some(index);
}
}
if let Some(active_item_index) = active_item_index {
pane.update(cx, |pane, cx| {
pane.activate_item(active_item_index, false, false, cx);
})?;
}
anyhow::Ok(items)
}
}
pub type GroupId = i64;
pub type PaneId = i64;
pub type ItemId = usize;
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct SerializedItem {
pub kind: Arc<str>,
pub item_id: ItemId,
pub active: bool,
}
impl SerializedItem {
pub fn new(kind: impl AsRef<str>, item_id: ItemId, active: bool) -> Self {
Self {
kind: Arc::from(kind.as_ref()),
item_id,
active,
}
}
}
#[cfg(test)]
impl Default for SerializedItem {
fn default() -> Self {
SerializedItem {
kind: Arc::from("Terminal"),
item_id: 100000,
active: false,
}
}
}
impl StaticColumnCount for SerializedItem {
fn column_count() -> usize {
3
}
}
impl Bind for &SerializedItem {
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
let next_index = statement.bind(&self.kind, start_index)?;
let next_index = statement.bind(&self.item_id, next_index)?;
statement.bind(&self.active, next_index)
}
}
impl Column for SerializedItem {
fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
let (kind, next_index) = Arc::<str>::column(statement, start_index)?;
let (item_id, next_index) = ItemId::column(statement, next_index)?;
let (active, next_index) = bool::column(statement, next_index)?;
Ok((
SerializedItem {
kind,
item_id,
active,
},
next_index,
))
}
}

File diff suppressed because it is too large Load diff

View file

@ -120,7 +120,7 @@ fn main() {
let node_runtime = RealNodeRuntime::new(http.clone());
language2::init(cx);
let user_store = cx.entity(|cx| UserStore::new(client.clone(), http.clone(), cx));
let user_store = cx.build_model(|cx| UserStore::new(client.clone(), http.clone(), cx));
// let workspace_store = cx.add_model(|cx| WorkspaceStore::new(client.clone(), cx));
cx.set_global(client.clone());

View file

@ -4,7 +4,7 @@ mod open_listener;
pub use assets::*;
use client2::{Client, UserStore};
use gpui2::{AsyncAppContext, Handle};
use gpui2::{AsyncAppContext, Model};
pub use only_instance::*;
pub use open_listener::*;
@ -47,7 +47,7 @@ pub fn connect_to_cli(
pub struct AppState {
pub client: Arc<Client>,
pub user_store: Handle<UserStore>,
pub user_store: Model<UserStore>,
}
pub async fn handle_cli_connection(