mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-12 21:32:40 +00:00
Keep weak handles to workspace items
This commit is contained in:
parent
e6323f0d02
commit
3c3cf3b7c5
2 changed files with 84 additions and 53 deletions
|
@ -2100,7 +2100,7 @@ impl<T: Entity> ModelHandle<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn downgrade(&self) -> WeakModelHandle<T> {
|
pub fn downgrade(&self) -> WeakModelHandle<T> {
|
||||||
WeakModelHandle::new(self.model_id)
|
WeakModelHandle::new(self.model_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2268,6 +2268,15 @@ impl<T: Entity> WeakModelHandle<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> Clone for WeakModelHandle<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
model_id: self.model_id,
|
||||||
|
model_type: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ViewHandle<T> {
|
pub struct ViewHandle<T> {
|
||||||
window_id: usize,
|
window_id: usize,
|
||||||
view_id: usize,
|
view_id: usize,
|
||||||
|
|
|
@ -1,14 +1,28 @@
|
||||||
pub mod pane;
|
pub mod pane;
|
||||||
pub mod pane_group;
|
pub mod pane_group;
|
||||||
|
use crate::{
|
||||||
|
editor::{Buffer, BufferView},
|
||||||
|
settings::Settings,
|
||||||
|
time::ReplicaId,
|
||||||
|
watch::{self, Receiver},
|
||||||
|
worktree::{FileHandle, Worktree, WorktreeHandle},
|
||||||
|
};
|
||||||
|
use futures_core::{future::LocalBoxFuture, Future};
|
||||||
|
use gpui::{
|
||||||
|
color::rgbu, elements::*, json::to_string_pretty, keymap::Binding, AnyViewHandle, AppContext,
|
||||||
|
ClipboardItem, Entity, EntityTask, ModelHandle, MutableAppContext, PathPromptOptions, View,
|
||||||
|
ViewContext, ViewHandle, WeakModelHandle,
|
||||||
|
};
|
||||||
|
use log::error;
|
||||||
pub use pane::*;
|
pub use pane::*;
|
||||||
pub use pane_group::*;
|
pub use pane_group::*;
|
||||||
|
use smol::prelude::*;
|
||||||
use crate::{
|
use std::{collections::HashMap, path::PathBuf};
|
||||||
settings::Settings,
|
use std::{
|
||||||
watch::{self, Receiver},
|
collections::{hash_map::Entry, HashSet},
|
||||||
worktree::FileHandle,
|
path::Path,
|
||||||
|
sync::Arc,
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, fmt, path::PathBuf};
|
|
||||||
|
|
||||||
pub fn init(app: &mut MutableAppContext) {
|
pub fn init(app: &mut MutableAppContext) {
|
||||||
app.add_global_action("workspace:open", open);
|
app.add_global_action("workspace:open", open);
|
||||||
|
@ -23,24 +37,6 @@ pub fn init(app: &mut MutableAppContext) {
|
||||||
]);
|
]);
|
||||||
pane::init(app);
|
pane::init(app);
|
||||||
}
|
}
|
||||||
use crate::{
|
|
||||||
editor::{Buffer, BufferView},
|
|
||||||
time::ReplicaId,
|
|
||||||
worktree::{Worktree, WorktreeHandle},
|
|
||||||
};
|
|
||||||
use futures_core::{future::LocalBoxFuture, Future};
|
|
||||||
use gpui::{
|
|
||||||
color::rgbu, elements::*, json::to_string_pretty, keymap::Binding, AnyViewHandle, AppContext,
|
|
||||||
ClipboardItem, Entity, EntityTask, ModelHandle, MutableAppContext, PathPromptOptions, View,
|
|
||||||
ViewContext, ViewHandle,
|
|
||||||
};
|
|
||||||
use log::error;
|
|
||||||
use smol::prelude::*;
|
|
||||||
use std::{
|
|
||||||
collections::{hash_map::Entry, HashSet},
|
|
||||||
path::Path,
|
|
||||||
sync::Arc,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct OpenParams {
|
pub struct OpenParams {
|
||||||
pub paths: Vec<PathBuf>,
|
pub paths: Vec<PathBuf>,
|
||||||
|
@ -137,15 +133,19 @@ pub trait ItemView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ItemHandle: Send + Sync {
|
pub trait ItemHandle: Send + Sync {
|
||||||
fn id(&self) -> usize;
|
fn boxed_clone(&self) -> Box<dyn ItemHandle>;
|
||||||
|
fn downgrade(&self) -> Box<dyn WeakItemHandle>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait WeakItemHandle: Send + Sync {
|
||||||
fn file<'a>(&'a self, ctx: &'a AppContext) -> Option<&'a FileHandle>;
|
fn file<'a>(&'a self, ctx: &'a AppContext) -> Option<&'a FileHandle>;
|
||||||
fn add_view(
|
fn add_view(
|
||||||
&self,
|
&self,
|
||||||
window_id: usize,
|
window_id: usize,
|
||||||
settings: watch::Receiver<Settings>,
|
settings: watch::Receiver<Settings>,
|
||||||
app: &mut MutableAppContext,
|
app: &mut MutableAppContext,
|
||||||
) -> Box<dyn ItemViewHandle>;
|
) -> Option<Box<dyn ItemViewHandle>>;
|
||||||
fn boxed_clone(&self) -> Box<dyn ItemHandle>;
|
fn alive(&self, ctx: &AppContext) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ItemViewHandle: Send + Sync {
|
pub trait ItemViewHandle: Send + Sync {
|
||||||
|
@ -165,25 +165,37 @@ pub trait ItemViewHandle: Send + Sync {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Item> ItemHandle for ModelHandle<T> {
|
impl<T: Item> ItemHandle for ModelHandle<T> {
|
||||||
fn id(&self) -> usize {
|
fn boxed_clone(&self) -> Box<dyn ItemHandle> {
|
||||||
self.id()
|
Box::new(self.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn downgrade(&self) -> Box<dyn WeakItemHandle> {
|
||||||
|
Box::new(self.downgrade())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Item> WeakItemHandle for WeakModelHandle<T> {
|
||||||
fn file<'a>(&'a self, ctx: &'a AppContext) -> Option<&'a FileHandle> {
|
fn file<'a>(&'a self, ctx: &'a AppContext) -> Option<&'a FileHandle> {
|
||||||
self.read(ctx).file()
|
self.upgrade(ctx).and_then(|h| h.read(ctx).file())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_view(
|
fn add_view(
|
||||||
&self,
|
&self,
|
||||||
window_id: usize,
|
window_id: usize,
|
||||||
settings: watch::Receiver<Settings>,
|
settings: Receiver<Settings>,
|
||||||
app: &mut MutableAppContext,
|
ctx: &mut MutableAppContext,
|
||||||
) -> Box<dyn ItemViewHandle> {
|
) -> Option<Box<dyn ItemViewHandle>> {
|
||||||
Box::new(app.add_view(window_id, |ctx| T::build_view(self.clone(), settings, ctx)))
|
if let Some(handle) = self.upgrade(ctx.as_ref()) {
|
||||||
|
Some(Box::new(ctx.add_view(window_id, |ctx| {
|
||||||
|
T::build_view(handle, settings, ctx)
|
||||||
|
})))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn boxed_clone(&self) -> Box<dyn ItemHandle> {
|
fn alive(&self, ctx: &AppContext) -> bool {
|
||||||
Box::new(self.clone())
|
self.upgrade(ctx).is_some()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,12 +268,6 @@ impl Clone for Box<dyn ItemHandle> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Box<dyn ItemHandle> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(f, "ItemHandle {{id: {}}}", self.id())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct State {
|
pub struct State {
|
||||||
pub modal: Option<usize>,
|
pub modal: Option<usize>,
|
||||||
|
@ -276,7 +282,7 @@ pub struct Workspace {
|
||||||
active_pane: ViewHandle<Pane>,
|
active_pane: ViewHandle<Pane>,
|
||||||
replica_id: ReplicaId,
|
replica_id: ReplicaId,
|
||||||
worktrees: HashSet<ModelHandle<Worktree>>,
|
worktrees: HashSet<ModelHandle<Worktree>>,
|
||||||
items: Vec<Box<dyn ItemHandle>>,
|
items: Vec<Box<dyn WeakItemHandle>>,
|
||||||
loading_items: HashMap<
|
loading_items: HashMap<
|
||||||
(usize, Arc<Path>),
|
(usize, Arc<Path>),
|
||||||
postage::watch::Receiver<Option<Result<Box<dyn ItemHandle>, Arc<anyhow::Error>>>>,
|
postage::watch::Receiver<Option<Result<Box<dyn ItemHandle>, Arc<anyhow::Error>>>>,
|
||||||
|
@ -427,7 +433,7 @@ impl Workspace {
|
||||||
let buffer = ctx.add_model(|ctx| Buffer::new(self.replica_id, "", ctx));
|
let buffer = ctx.add_model(|ctx| Buffer::new(self.replica_id, "", ctx));
|
||||||
let buffer_view =
|
let buffer_view =
|
||||||
ctx.add_view(|ctx| BufferView::for_buffer(buffer.clone(), self.settings.clone(), ctx));
|
ctx.add_view(|ctx| BufferView::for_buffer(buffer.clone(), self.settings.clone(), ctx));
|
||||||
self.items.push(Box::new(buffer));
|
self.items.push(ItemHandle::downgrade(&buffer));
|
||||||
self.add_item(Box::new(buffer_view), ctx);
|
self.add_item(Box::new(buffer_view), ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -451,12 +457,25 @@ impl Workspace {
|
||||||
|
|
||||||
// Otherwise, if this file is already open somewhere in the workspace,
|
// Otherwise, if this file is already open somewhere in the workspace,
|
||||||
// then add another view for it.
|
// then add another view for it.
|
||||||
if let Some(item) = self.items.iter().find(|item| {
|
let mut i = 0;
|
||||||
item.file(ctx.as_ref())
|
while i < self.items.len() {
|
||||||
.map_or(false, |f| f.entry_id() == entry)
|
let item = &self.items[i];
|
||||||
}) {
|
if item.alive(ctx.as_ref()) {
|
||||||
self.add_item(item.add_view(window_id, settings, ctx.as_mut()), ctx);
|
if item
|
||||||
return None;
|
.file(ctx.as_ref())
|
||||||
|
.map_or(false, |f| f.entry_id() == entry)
|
||||||
|
{
|
||||||
|
self.add_item(
|
||||||
|
item.add_view(window_id, settings.clone(), ctx.as_mut())
|
||||||
|
.unwrap(),
|
||||||
|
ctx,
|
||||||
|
);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
} else {
|
||||||
|
self.items.remove(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (worktree_id, path) = entry.clone();
|
let (worktree_id, path) = entry.clone();
|
||||||
|
@ -507,8 +526,11 @@ impl Workspace {
|
||||||
me.loading_items.remove(&entry);
|
me.loading_items.remove(&entry);
|
||||||
match load_result {
|
match load_result {
|
||||||
Ok(item) => {
|
Ok(item) => {
|
||||||
me.items.push(item.clone());
|
let weak_item = item.downgrade();
|
||||||
let view = item.add_view(window_id, settings, ctx.as_mut());
|
let view = weak_item
|
||||||
|
.add_view(window_id, settings, ctx.as_mut())
|
||||||
|
.unwrap();
|
||||||
|
me.items.push(weak_item);
|
||||||
me.add_item(view, ctx);
|
me.add_item(view, ctx);
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
|
|
Loading…
Reference in a new issue