Enable reload of images in image viewer (#20374)

Closes #11529

Release Notes:

- Fixed an issue where the image preview would not update when the
underlying file changed

---------

Co-authored-by: Bennet <bennet@zed.dev>
This commit is contained in:
Will Bradley 2024-11-10 03:37:02 -07:00 committed by GitHub
parent f3320998a8
commit 0dbda71423
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 840 additions and 109 deletions

View file

@ -2,6 +2,7 @@ pub mod buffer_store;
mod color_extractor;
pub mod connection_manager;
pub mod debounced_delay;
pub mod image_store;
pub mod lsp_command;
pub mod lsp_ext_command;
pub mod lsp_store;
@ -35,6 +36,8 @@ use futures::{
future::try_join_all,
StreamExt,
};
pub use image_store::{ImageItem, ImageStore};
use image_store::{ImageItemEvent, ImageStoreEvent};
use git::{blame::Blame, repository::GitRepository};
use gpui::{
@ -146,6 +149,7 @@ pub struct Project {
client_subscriptions: Vec<client::Subscription>,
worktree_store: Model<WorktreeStore>,
buffer_store: Model<BufferStore>,
image_store: Model<ImageStore>,
lsp_store: Model<LspStore>,
_subscriptions: Vec<gpui::Subscription>,
buffers_needing_diff: HashSet<WeakModel<Buffer>>,
@ -205,10 +209,11 @@ enum BufferOrderedMessage {
#[derive(Debug)]
enum ProjectClientState {
/// Single-player mode.
Local,
Shared {
remote_id: u64,
},
/// Multi-player mode but still a local project.
Shared { remote_id: u64 },
/// Multi-player mode but working on a remote project.
Remote {
sharing_has_stopped: bool,
capability: Capability,
@ -606,6 +611,10 @@ impl Project {
cx.subscribe(&buffer_store, Self::on_buffer_store_event)
.detach();
let image_store = cx.new_model(|cx| ImageStore::local(worktree_store.clone(), cx));
cx.subscribe(&image_store, Self::on_image_store_event)
.detach();
let prettier_store = cx.new_model(|cx| {
PrettierStore::new(
node.clone(),
@ -666,6 +675,7 @@ impl Project {
collaborators: Default::default(),
worktree_store,
buffer_store,
image_store,
lsp_store,
join_project_response_message_id: 0,
client_state: ProjectClientState::Local,
@ -729,6 +739,14 @@ impl Project {
cx,
)
});
let image_store = cx.new_model(|cx| {
ImageStore::remote(
worktree_store.clone(),
ssh.read(cx).proto_client(),
SSH_PROJECT_ID,
cx,
)
});
cx.subscribe(&buffer_store, Self::on_buffer_store_event)
.detach();
@ -774,6 +792,7 @@ impl Project {
collaborators: Default::default(),
worktree_store,
buffer_store,
image_store,
lsp_store,
join_project_response_message_id: 0,
client_state: ProjectClientState::Local,
@ -920,6 +939,9 @@ impl Project {
let buffer_store = cx.new_model(|cx| {
BufferStore::remote(worktree_store.clone(), client.clone().into(), remote_id, cx)
})?;
let image_store = cx.new_model(|cx| {
ImageStore::remote(worktree_store.clone(), client.clone().into(), remote_id, cx)
})?;
let lsp_store = cx.new_model(|cx| {
let mut lsp_store = LspStore::new_remote(
@ -982,6 +1004,7 @@ impl Project {
let mut this = Self {
buffer_ordered_messages_tx: tx,
buffer_store: buffer_store.clone(),
image_store,
worktree_store: worktree_store.clone(),
lsp_store: lsp_store.clone(),
active_entry: None,
@ -1783,7 +1806,7 @@ impl Project {
path: impl Into<ProjectPath>,
cx: &mut ModelContext<Self>,
) -> Task<Result<Model<Buffer>>> {
if (self.is_via_collab() || self.is_via_ssh()) && self.is_disconnected(cx) {
if self.is_disconnected(cx) {
return Task::ready(Err(anyhow!(ErrorCode::Disconnected)));
}
@ -1879,6 +1902,20 @@ impl Project {
Ok(())
}
pub fn open_image(
&mut self,
path: impl Into<ProjectPath>,
cx: &mut ModelContext<Self>,
) -> Task<Result<Model<ImageItem>>> {
if self.is_disconnected(cx) {
return Task::ready(Err(anyhow!(ErrorCode::Disconnected)));
}
self.image_store.update(cx, |image_store, cx| {
image_store.open_image(path.into(), cx)
})
}
async fn send_buffer_ordered_messages(
this: WeakModel<Self>,
rx: UnboundedReceiver<BufferOrderedMessage>,
@ -2013,6 +2050,22 @@ impl Project {
}
}
fn on_image_store_event(
&mut self,
_: Model<ImageStore>,
event: &ImageStoreEvent,
cx: &mut ModelContext<Self>,
) {
match event {
ImageStoreEvent::ImageAdded(image) => {
cx.subscribe(image, |this, image, event, cx| {
this.on_image_event(image, event, cx);
})
.detach();
}
}
}
fn on_lsp_store_event(
&mut self,
_: Model<LspStore>,
@ -2253,6 +2306,25 @@ impl Project {
None
}
fn on_image_event(
&mut self,
image: Model<ImageItem>,
event: &ImageItemEvent,
cx: &mut ModelContext<Self>,
) -> Option<()> {
match event {
ImageItemEvent::ReloadNeeded => {
if !self.is_via_collab() {
self.reload_images([image.clone()].into_iter().collect(), cx)
.detach_and_log_err(cx);
}
}
_ => {}
}
None
}
fn request_buffer_diff_recalculation(
&mut self,
buffer: &Model<Buffer>,
@ -2466,6 +2538,15 @@ impl Project {
})
}
pub fn reload_images(
&self,
images: HashSet<Model<ImageItem>>,
cx: &mut ModelContext<Self>,
) -> Task<Result<()>> {
self.image_store
.update(cx, |image_store, cx| image_store.reload_images(images, cx))
}
pub fn format(
&mut self,
buffers: HashSet<Model<Buffer>>,