Add the entity trait and implement for models, views, subscriptions, and observations

This commit is contained in:
Mikayla 2023-10-30 17:43:07 -07:00
parent 58446c2715
commit 327a2f9967
No known key found for this signature in database
13 changed files with 183 additions and 101 deletions

View file

@ -67,8 +67,8 @@ impl ActiveCall {
incoming_call: watch::channel(),
_subscriptions: vec![
client.add_request_handler(cx.weak_handle(), Self::handle_incoming_call),
client.add_message_handler(cx.weak_handle(), Self::handle_call_canceled),
client.add_request_handler(cx.weak_model(), Self::handle_incoming_call),
client.add_message_handler(cx.weak_model(), Self::handle_call_canceled),
],
client,
user_store,

View file

@ -122,9 +122,9 @@ impl UserStore {
let (mut current_user_tx, current_user_rx) = watch::channel();
let (update_contacts_tx, mut update_contacts_rx) = mpsc::unbounded();
let rpc_subscriptions = vec![
client.add_message_handler(cx.weak_handle(), Self::handle_update_contacts),
client.add_message_handler(cx.weak_handle(), Self::handle_update_invite_info),
client.add_message_handler(cx.weak_handle(), Self::handle_show_contacts),
client.add_message_handler(cx.weak_model(), Self::handle_update_contacts),
client.add_message_handler(cx.weak_model(), Self::handle_update_invite_info),
client.add_message_handler(cx.weak_model(), Self::handle_show_contacts),
];
Self {
users: Default::default(),

View file

@ -7,8 +7,8 @@ use async_tar::Archive;
use collections::{HashMap, HashSet};
use futures::{channel::oneshot, future::Shared, Future, FutureExt, TryFutureExt};
use gpui2::{
AppContext, AsyncAppContext, Context, EntityId, EventEmitter, Model, ModelContext, Task,
WeakModel,
AppContext, AsyncAppContext, Context, Entity, EntityId, EventEmitter, Model, ModelContext,
Task, WeakModel,
};
use language2::{
language_settings::{all_language_settings, language_settings},

View file

@ -726,7 +726,7 @@ impl Context for AppContext {
/// Update the entity referenced by the given model. The function is passed a mutable reference to the
/// entity along with a `ModelContext` for the entity.
fn update_entity<T: 'static, R>(
fn update_model<T: 'static, R>(
&mut self,
model: &Model<T>,
update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R,

View file

@ -32,7 +32,7 @@ impl Context for AsyncAppContext {
Ok(lock.build_model(build_model))
}
fn update_entity<T: 'static, R>(
fn update_model<T: 'static, R>(
&mut self,
handle: &Model<T>,
update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R,
@ -42,7 +42,7 @@ impl Context for AsyncAppContext {
.upgrade()
.ok_or_else(|| anyhow!("app was released"))?;
let mut lock = app.lock(); // Need this to compile
Ok(lock.update_entity(handle, update))
Ok(lock.update_model(handle, update))
}
}
@ -230,13 +230,13 @@ impl Context for AsyncWindowContext {
.update_window(self.window, |cx| cx.build_model(build_model))
}
fn update_entity<T: 'static, R>(
fn update_model<T: 'static, R>(
&mut self,
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))
.update_window(self.window, |cx| cx.update_model(handle, update))
}
}

View file

@ -1,4 +1,4 @@
use crate::{AnyBox, AppContext, Context};
use crate::{private::Sealed, AnyBox, AppContext, Context, Entity};
use anyhow::{anyhow, Result};
use derive_more::{Deref, DerefMut};
use parking_lot::{RwLock, RwLockUpgradableReadGuard};
@ -253,6 +253,32 @@ pub struct Model<T> {
unsafe impl<T> Send for Model<T> {}
unsafe impl<T> Sync for Model<T> {}
impl<T> Sealed for Model<T> {}
impl<T: 'static> Entity<T> for Model<T> {
type Weak = WeakModel<T>;
fn entity_id(&self) -> EntityId {
self.any_model.entity_id
}
fn downgrade(&self) -> Self::Weak {
WeakModel {
any_model: self.any_model.downgrade(),
entity_type: self.entity_type,
}
}
fn upgrade_from(weak: &Self::Weak) -> Option<Self>
where
Self: Sized,
{
Some(Model {
any_model: weak.any_model.upgrade()?,
entity_type: weak.entity_type,
})
}
}
impl<T: 'static> Model<T> {
fn new(id: EntityId, entity_map: Weak<RwLock<EntityRefCounts>>) -> Self
@ -265,11 +291,12 @@ impl<T: 'static> Model<T> {
}
}
/// Downgrade the this to a weak model reference
pub fn downgrade(&self) -> WeakModel<T> {
WeakModel {
any_model: self.any_model.downgrade(),
entity_type: self.entity_type,
}
// Delegate to the trait implementation to keep behavior in one place.
// This method was included to improve method resolution in the presence of
// the Model's deref
Entity::downgrade(self)
}
/// Convert this into a dynamically typed model.
@ -294,7 +321,7 @@ impl<T: 'static> Model<T> {
where
C: Context,
{
cx.update_entity(self, update)
cx.update_model(self, update)
}
}
@ -334,7 +361,7 @@ impl<T> Eq for Model<T> {}
impl<T> PartialEq<WeakModel<T>> for Model<T> {
fn eq(&self, other: &WeakModel<T>) -> bool {
self.entity_id() == other.entity_id()
self.any_model.entity_id() == other.entity_id()
}
}
@ -415,11 +442,10 @@ impl<T> Clone for WeakModel<T> {
}
impl<T: 'static> WeakModel<T> {
/// Upgrade this weak model reference into a strong model reference
pub fn upgrade(&self) -> Option<Model<T>> {
Some(Model {
any_model: self.any_model.upgrade()?,
entity_type: self.entity_type,
})
// Delegate to the trait implementation to keep behavior in one place.
Model::upgrade_from(self)
}
/// Update the entity referenced by this model with the given function if
@ -441,7 +467,7 @@ impl<T: 'static> WeakModel<T> {
crate::Flatten::flatten(
self.upgrade()
.ok_or_else(|| anyhow!("entity release"))
.map(|this| cx.update_entity(&this, update)),
.map(|this| cx.update_model(&this, update)),
)
}
}
@ -462,6 +488,6 @@ impl<T> Eq for WeakModel<T> {}
impl<T> PartialEq<Model<T>> for WeakModel<T> {
fn eq(&self, other: &Model<T>) -> bool {
self.entity_id() == other.entity_id()
self.entity_id() == other.any_model.entity_id()
}
}

View file

@ -1,6 +1,6 @@
use crate::{
AppContext, AsyncAppContext, Context, Effect, EntityId, EventEmitter, MainThread, Model,
Reference, Subscription, Task, WeakModel,
AppContext, AsyncAppContext, Context, Effect, Entity, EntityId, EventEmitter, MainThread,
Model, Reference, Subscription, Task, WeakModel,
};
use derive_more::{Deref, DerefMut};
use futures::FutureExt;
@ -31,29 +31,32 @@ impl<'a, T: 'static> ModelContext<'a, T> {
}
pub fn handle(&self) -> Model<T> {
self.weak_handle()
self.weak_model()
.upgrade()
.expect("The entity must be alive if we have a model context")
}
pub fn weak_handle(&self) -> WeakModel<T> {
pub fn weak_model(&self) -> WeakModel<T> {
self.model_state.clone()
}
pub fn observe<T2: 'static>(
pub fn observe<T2, E>(
&mut self,
handle: &Model<T2>,
mut on_notify: impl FnMut(&mut T, Model<T2>, &mut ModelContext<'_, T>) + Send + 'static,
entity: &E,
mut on_notify: impl FnMut(&mut T, E, &mut ModelContext<'_, T>) + Send + 'static,
) -> Subscription
where
T: 'static + Send,
T2: 'static,
E: Entity<T2>,
{
let this = self.weak_handle();
let handle = handle.downgrade();
let this = self.weak_model();
let entity_id = entity.entity_id();
let handle = entity.downgrade();
self.app.observers.insert(
handle.entity_id,
entity_id,
Box::new(move |cx| {
if let Some((this, handle)) = this.upgrade().zip(handle.upgrade()) {
if let Some((this, handle)) = this.upgrade().zip(E::upgrade_from(&handle)) {
this.update(cx, |this, cx| on_notify(this, handle, cx));
true
} else {
@ -63,21 +66,24 @@ impl<'a, T: 'static> ModelContext<'a, T> {
)
}
pub fn subscribe<E: 'static + EventEmitter>(
pub fn subscribe<T2, E>(
&mut self,
handle: &Model<E>,
mut on_event: impl FnMut(&mut T, Model<E>, &E::Event, &mut ModelContext<'_, T>) + Send + 'static,
entity: &E,
mut on_event: impl FnMut(&mut T, E, &T2::Event, &mut ModelContext<'_, T>) + Send + 'static,
) -> Subscription
where
T: 'static + Send,
T2: 'static + EventEmitter,
E: Entity<T2>,
{
let this = self.weak_handle();
let handle = handle.downgrade();
let this = self.weak_model();
let entity_id = entity.entity_id();
let entity = entity.downgrade();
self.app.event_listeners.insert(
handle.entity_id,
entity_id,
Box::new(move |event, cx| {
let event: &E::Event = event.downcast_ref().expect("invalid event type");
if let Some((this, handle)) = this.upgrade().zip(handle.upgrade()) {
let event: &T2::Event = event.downcast_ref().expect("invalid event type");
if let Some((this, handle)) = this.upgrade().zip(E::upgrade_from(&entity)) {
this.update(cx, |this, cx| on_event(this, handle, event, cx));
true
} else {
@ -103,17 +109,20 @@ impl<'a, T: 'static> ModelContext<'a, T> {
)
}
pub fn observe_release<E: 'static>(
pub fn observe_release<T2, E>(
&mut self,
handle: &Model<E>,
mut on_release: impl FnMut(&mut T, &mut E, &mut ModelContext<'_, T>) + Send + 'static,
entity: &E,
mut on_release: impl FnMut(&mut T, &mut T2, &mut ModelContext<'_, T>) + Send + 'static,
) -> Subscription
where
T: Any + Send,
T2: 'static,
E: Entity<T2>,
{
let this = self.weak_handle();
let entity_id = entity.entity_id();
let this = self.weak_model();
self.app.release_listeners.insert(
handle.entity_id,
entity_id,
Box::new(move |entity, cx| {
let entity = entity.downcast_mut().expect("invalid entity type");
if let Some(this) = this.upgrade() {
@ -130,7 +139,7 @@ impl<'a, T: 'static> ModelContext<'a, T> {
where
T: 'static + Send,
{
let handle = self.weak_handle();
let handle = self.weak_model();
self.global_observers.insert(
TypeId::of::<G>(),
Box::new(move |cx| handle.update(cx, |view, cx| f(view, cx)).is_ok()),
@ -145,7 +154,7 @@ impl<'a, T: 'static> ModelContext<'a, T> {
Fut: 'static + Future<Output = ()> + Send,
T: 'static + Send,
{
let handle = self.weak_handle();
let handle = self.weak_model();
self.app.quit_observers.insert(
(),
Box::new(move |cx| {
@ -191,7 +200,7 @@ impl<'a, T: 'static> ModelContext<'a, T> {
Fut: Future<Output = R> + Send + 'static,
R: Send + 'static,
{
let this = self.weak_handle();
let this = self.weak_model();
self.app.spawn(|cx| f(this, cx))
}
@ -203,7 +212,7 @@ impl<'a, T: 'static> ModelContext<'a, T> {
Fut: Future<Output = R> + 'static,
R: Send + 'static,
{
let this = self.weak_handle();
let this = self.weak_model();
self.app.spawn_on_main(|cx| f(this, cx))
}
}
@ -235,12 +244,12 @@ impl<'a, T> Context for ModelContext<'a, T> {
self.app.build_model(build_model)
}
fn update_entity<U: 'static, R>(
fn update_model<U: 'static, R>(
&mut self,
handle: &Model<U>,
update: impl FnOnce(&mut U, &mut Self::ModelContext<'_, U>) -> R,
) -> R {
self.app.update_entity(handle, update)
self.app.update_model(handle, update)
}
}

View file

@ -26,13 +26,13 @@ impl Context for TestAppContext {
lock.build_model(build_model)
}
fn update_entity<T: 'static, R>(
fn update_model<T: 'static, R>(
&mut self,
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)
lock.update_model(handle, update)
}
}

View file

@ -24,6 +24,12 @@ mod util;
mod view;
mod window;
mod private {
/// A mechanism for restricting implementations of a trait to only those in GPUI.
/// See: https://predr.ag/blog/definitive-guide-to-sealed-traits-in-rust/
pub trait Sealed {}
}
pub use action::*;
pub use anyhow::Result;
pub use app::*;
@ -39,6 +45,7 @@ pub use image_cache::*;
pub use interactive::*;
pub use keymap::*;
pub use platform::*;
use private::Sealed;
pub use refineable::*;
pub use scene::*;
pub use serde;
@ -80,7 +87,7 @@ pub trait Context {
where
T: 'static + Send;
fn update_entity<T: 'static, R>(
fn update_model<T: 'static, R>(
&mut self,
handle: &Model<T>,
update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R,
@ -104,6 +111,16 @@ pub trait VisualContext: Context {
) -> Self::Result<R>;
}
pub trait Entity<T>: Sealed {
type Weak: 'static + Send;
fn entity_id(&self) -> EntityId;
fn downgrade(&self) -> Self::Weak;
fn upgrade_from(weak: &Self::Weak) -> Option<Self>
where
Self: Sized;
}
pub enum GlobalKey {
Numeric(usize),
View(EntityId),
@ -149,12 +166,12 @@ impl<C: Context> Context for MainThread<C> {
})
}
fn update_entity<T: 'static, R>(
fn update_model<T: 'static, R>(
&mut self,
handle: &Model<T>,
update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R,
) -> Self::Result<R> {
self.0.update_entity(handle, |entity, cx| {
self.0.update_model(handle, |entity, cx| {
let cx = unsafe {
mem::transmute::<
&mut C::ModelContext<'_, T>,

View file

@ -1,7 +1,7 @@
use crate::{
AnyBox, AnyElement, AnyModel, AppContext, AvailableSpace, BorrowWindow, Bounds, Component,
Element, ElementId, EntityId, LayoutId, Model, Pixels, Size, ViewContext, VisualContext,
WeakModel, WindowContext,
private::Sealed, AnyBox, AnyElement, AnyModel, AppContext, AvailableSpace, BorrowWindow,
Bounds, Component, Element, ElementId, Entity, EntityId, LayoutId, Model, Pixels, Size,
ViewContext, VisualContext, WeakModel, WindowContext,
};
use anyhow::{Context, Result};
use std::{any::TypeId, marker::PhantomData, sync::Arc};
@ -16,19 +16,42 @@ pub struct View<V> {
pub(crate) model: Model<V>,
}
impl<V> Sealed for View<V> {}
impl<V: Render> View<V> {
pub fn into_any(self) -> AnyView {
AnyView(Arc::new(self))
}
}
impl<V: 'static> View<V> {
pub fn downgrade(&self) -> WeakView<V> {
impl<V: 'static> Entity<V> for View<V> {
type Weak = WeakView<V>;
fn entity_id(&self) -> EntityId {
self.model.entity_id
}
fn downgrade(&self) -> Self::Weak {
WeakView {
model: self.model.downgrade(),
}
}
fn upgrade_from(weak: &Self::Weak) -> Option<Self>
where
Self: Sized,
{
let model = weak.model.upgrade()?;
Some(View { model })
}
}
impl<V: 'static> View<V> {
/// Convert this strong view reference into a weak view reference.
pub fn downgrade(&self) -> WeakView<V> {
Entity::downgrade(self)
}
pub fn update<C, R>(
&self,
cx: &mut C,
@ -111,8 +134,7 @@ pub struct WeakView<V> {
impl<V: 'static> WeakView<V> {
pub fn upgrade(&self) -> Option<View<V>> {
let model = self.model.upgrade()?;
Some(View { model })
Entity::upgrade_from(self)
}
pub fn update<R>(
@ -200,7 +222,7 @@ where
}
fn entity_id(&self) -> EntityId {
self.model.entity_id
Entity::entity_id(self)
}
fn model(&self) -> AnyModel {
@ -208,7 +230,7 @@ where
}
fn initialize(&self, cx: &mut WindowContext) -> AnyBox {
cx.with_element_id(self.entity_id(), |_global_id, cx| {
cx.with_element_id(ViewObject::entity_id(self), |_global_id, cx| {
self.update(cx, |state, cx| {
let mut any_element = Box::new(AnyElement::new(state.render(cx)));
any_element.initialize(state, cx);
@ -218,7 +240,7 @@ where
}
fn layout(&self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId {
cx.with_element_id(self.entity_id(), |_global_id, cx| {
cx.with_element_id(ViewObject::entity_id(self), |_global_id, cx| {
self.update(cx, |state, cx| {
let element = element.downcast_mut::<AnyElement<V>>().unwrap();
element.layout(state, cx)
@ -227,7 +249,7 @@ where
}
fn paint(&self, _: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext) {
cx.with_element_id(self.entity_id(), |_global_id, cx| {
cx.with_element_id(ViewObject::entity_id(self), |_global_id, cx| {
self.update(cx, |state, cx| {
let element = element.downcast_mut::<AnyElement<V>>().unwrap();
element.paint(state, cx);

View file

@ -1,8 +1,8 @@
use crate::{
px, size, Action, AnyBox, AnyDrag, AnyView, AppContext, AsyncWindowContext, AvailableSpace,
Bounds, BoxShadow, Context, Corners, DevicePixels, DispatchContext, DisplayId, Edges, Effect,
EntityId, EventEmitter, FileDropEvent, FocusEvent, FontId, GlobalElementId, GlyphId, Hsla,
ImageData, InputEvent, IsZero, KeyListener, KeyMatch, KeyMatcher, Keystroke, LayoutId,
Entity, EntityId, EventEmitter, FileDropEvent, FocusEvent, FontId, GlobalElementId, 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,
@ -1253,7 +1253,7 @@ impl Context for WindowContext<'_, '_> {
self.entities.insert(slot, model)
}
fn update_entity<T: 'static, R>(
fn update_model<T: 'static, R>(
&mut self,
model: &Model<T>,
update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R,
@ -1568,23 +1568,25 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
self.window_cx.on_next_frame(move |cx| view.update(cx, f));
}
pub fn observe<E>(
pub fn observe<V2, E>(
&mut self,
handle: &Model<E>,
mut on_notify: impl FnMut(&mut V, Model<E>, &mut ViewContext<'_, '_, V>) + Send + 'static,
entity: &E,
mut on_notify: impl FnMut(&mut V, E, &mut ViewContext<'_, '_, V>) + Send + 'static,
) -> Subscription
where
E: 'static,
V2: 'static,
V: Any + Send,
E: Entity<V2>,
{
let view = self.view();
let handle = handle.downgrade();
let entity_id = entity.entity_id();
let entity = entity.downgrade();
let window_handle = self.window.handle;
self.app.observers.insert(
handle.entity_id,
entity_id,
Box::new(move |cx| {
cx.update_window(window_handle.id, |cx| {
if let Some(handle) = handle.upgrade() {
if let Some(handle) = E::upgrade_from(&entity) {
view.update(cx, |this, cx| on_notify(this, handle, cx))
.is_ok()
} else {
@ -1596,21 +1598,24 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
)
}
pub fn subscribe<E: EventEmitter>(
pub fn subscribe<V2, E>(
&mut self,
handle: &Model<E>,
mut on_event: impl FnMut(&mut V, Model<E>, &E::Event, &mut ViewContext<'_, '_, V>)
+ Send
+ 'static,
) -> Subscription {
entity: &E,
mut on_event: impl FnMut(&mut V, E, &V2::Event, &mut ViewContext<'_, '_, V>) + Send + 'static,
) -> Subscription
where
V2: EventEmitter,
E: Entity<V2>,
{
let view = self.view();
let handle = handle.downgrade();
let entity_id = entity.entity_id();
let handle = entity.downgrade();
let window_handle = self.window.handle;
self.app.event_listeners.insert(
handle.entity_id,
entity_id,
Box::new(move |event, cx| {
cx.update_window(window_handle.id, |cx| {
if let Some(handle) = handle.upgrade() {
if let Some(handle) = E::upgrade_from(&handle) {
let event = event.downcast_ref().expect("invalid event type");
view.update(cx, |this, cx| on_event(this, handle, event, cx))
.is_ok()
@ -1638,18 +1643,21 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
)
}
pub fn observe_release<T: 'static>(
pub fn observe_release<V2, E>(
&mut self,
handle: &Model<T>,
mut on_release: impl FnMut(&mut V, &mut T, &mut ViewContext<'_, '_, V>) + Send + 'static,
entity: &E,
mut on_release: impl FnMut(&mut V, &mut V2, &mut ViewContext<'_, '_, V>) + Send + 'static,
) -> Subscription
where
V: Any + Send,
V2: 'static,
E: Entity<V2>,
{
let view = self.view();
let entity_id = entity.entity_id();
let window_handle = self.window.handle;
self.app.release_listeners.insert(
handle.entity_id,
entity_id,
Box::new(move |entity, cx| {
let entity = entity.downcast_mut().expect("invalid entity type");
let _ = cx.update_window(window_handle.id, |cx| {
@ -1864,12 +1872,12 @@ impl<'a, 'w, V> Context for ViewContext<'a, 'w, V> {
self.window_cx.build_model(build_model)
}
fn update_entity<T: 'static, R>(
fn update_model<T: 'static, R>(
&mut self,
model: &Model<T>,
update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R,
) -> R {
self.window_cx.update_entity(model, update)
self.window_cx.update_model(model, update)
}
}

View file

@ -26,8 +26,8 @@ use futures::{
};
use globset::{Glob, GlobSet, GlobSetBuilder};
use gpui2::{
AnyModel, AppContext, AsyncAppContext, Context, EventEmitter, Executor, Model, ModelContext,
Task, WeakModel,
AnyModel, AppContext, AsyncAppContext, Context, Entity, EventEmitter, Executor, Model,
ModelContext, Task, WeakModel,
};
use itertools::Itertools;
use language2::{
@ -2491,7 +2491,7 @@ impl Project {
delay
} else {
if first_insertion {
let this = cx.weak_handle();
let this = cx.weak_model();
cx.defer(move |cx| {
if let Some(this) = this.upgrade() {
this.update(cx, |this, cx| {
@ -8650,7 +8650,7 @@ fn subscribe_for_copilot_events(
// Another event wants to re-add the server that was already added and subscribed to, avoid doing it again.
if !copilot_server.has_notification_handler::<copilot2::request::LogMessage>() {
let new_server_id = copilot_server.server_id();
let weak_project = cx.weak_handle();
let weak_project = cx.weak_model();
let copilot_log_subscription = copilot_server
.on_notification::<copilot2::request::LogMessage, _>(
move |params, mut cx| {

View file

@ -1,5 +1,5 @@
use crate::Project;
use gpui2::{AnyWindowHandle, Context, Model, ModelContext, WeakModel};
use gpui2::{AnyWindowHandle, Context, Entity, Model, ModelContext, WeakModel};
use settings2::Settings;
use std::path::{Path, PathBuf};
use terminal2::{