Fix item closing overly triggering save dialogues (#21374)

Closes https://github.com/zed-industries/zed/issues/12029

Allows to introspect project items inside items more deeply, checking
them for being dirty.
For that:
* renames `project::Item` into `project::ProjectItem`
* adds an `is_dirty(&self) -> bool` method to the renamed trait
* changes the closing logic to only care about dirty project items when
checking for save prompts conditions
* save prompts are raised only if the item is singleton without a
project path; or if the item has dirty project items that are not open
elsewhere

Release Notes:

- Fixed item closing overly triggering save dialogues
This commit is contained in:
Kirill Bulatov 2024-12-01 01:48:31 +02:00 committed by GitHub
parent c2cd84a749
commit 28849dd2a8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 600 additions and 85 deletions

View file

@ -208,7 +208,7 @@ pub trait Item: FocusableView + EventEmitter<Self::Event> {
fn for_each_project_item(
&self,
_: &AppContext,
_: &mut dyn FnMut(EntityId, &dyn project::Item),
_: &mut dyn FnMut(EntityId, &dyn project::ProjectItem),
) {
}
fn is_singleton(&self, _cx: &AppContext) -> bool {
@ -386,7 +386,7 @@ pub trait ItemHandle: 'static + Send {
fn for_each_project_item(
&self,
_: &AppContext,
_: &mut dyn FnMut(EntityId, &dyn project::Item),
_: &mut dyn FnMut(EntityId, &dyn project::ProjectItem),
);
fn is_singleton(&self, cx: &AppContext) -> bool;
fn boxed_clone(&self) -> Box<dyn ItemHandle>;
@ -563,7 +563,7 @@ impl<T: Item> ItemHandle for View<T> {
fn for_each_project_item(
&self,
cx: &AppContext,
f: &mut dyn FnMut(EntityId, &dyn project::Item),
f: &mut dyn FnMut(EntityId, &dyn project::ProjectItem),
) {
self.read(cx).for_each_project_item(cx, f)
}
@ -891,7 +891,7 @@ impl<T: Item> WeakItemHandle for WeakView<T> {
}
pub trait ProjectItem: Item {
type Item: project::Item;
type Item: project::ProjectItem;
fn for_project_item(
project: Model<Project>,
@ -1045,6 +1045,7 @@ pub mod test {
pub struct TestProjectItem {
pub entry_id: Option<ProjectEntryId>,
pub project_path: Option<ProjectPath>,
pub is_dirty: bool,
}
pub struct TestItem {
@ -1065,7 +1066,7 @@ pub mod test {
focus_handle: gpui::FocusHandle,
}
impl project::Item for TestProjectItem {
impl project::ProjectItem for TestProjectItem {
fn try_open(
_project: &Model<Project>,
_path: &ProjectPath,
@ -1073,7 +1074,6 @@ pub mod test {
) -> Option<Task<gpui::Result<Model<Self>>>> {
None
}
fn entry_id(&self, _: &AppContext) -> Option<ProjectEntryId> {
self.entry_id
}
@ -1081,6 +1081,10 @@ pub mod test {
fn project_path(&self, _: &AppContext) -> Option<ProjectPath> {
self.project_path.clone()
}
fn is_dirty(&self) -> bool {
self.is_dirty
}
}
pub enum TestItemEvent {
@ -1097,6 +1101,7 @@ pub mod test {
cx.new_model(|_| Self {
entry_id,
project_path,
is_dirty: false,
})
}
@ -1104,6 +1109,7 @@ pub mod test {
cx.new_model(|_| Self {
project_path: None,
entry_id: None,
is_dirty: false,
})
}
}
@ -1225,7 +1231,7 @@ pub mod test {
fn for_each_project_item(
&self,
cx: &AppContext,
f: &mut dyn FnMut(EntityId, &dyn project::Item),
f: &mut dyn FnMut(EntityId, &dyn project::ProjectItem),
) {
self.project_items
.iter()