Skip to content

Commit 28849dd

Browse files
Fix item closing overly triggering save dialogues (#21374)
Closes #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
1 parent c2cd84a commit 28849dd

File tree

19 files changed

+599
-84
lines changed

19 files changed

+599
-84
lines changed

crates/diagnostics/src/diagnostics.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -716,7 +716,7 @@ impl Item for ProjectDiagnosticsEditor {
716716
fn for_each_project_item(
717717
&self,
718718
cx: &AppContext,
719-
f: &mut dyn FnMut(gpui::EntityId, &dyn project::Item),
719+
f: &mut dyn FnMut(gpui::EntityId, &dyn project::ProjectItem),
720720
) {
721721
self.editor.for_each_project_item(cx, f)
722722
}

crates/editor/src/editor.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ use parking_lot::{Mutex, RwLock};
125125
use project::{
126126
lsp_store::{FormatTarget, FormatTrigger},
127127
project_settings::{GitGutterSetting, ProjectSettings},
128-
CodeAction, Completion, CompletionIntent, DocumentHighlight, InlayHint, Item, Location,
129-
LocationLink, Project, ProjectTransaction, TaskSourceKind,
128+
CodeAction, Completion, CompletionIntent, DocumentHighlight, InlayHint, Location, LocationLink,
129+
Project, ProjectItem, ProjectTransaction, TaskSourceKind,
130130
};
131131
use rand::prelude::*;
132132
use rpc::{proto::*, ErrorExt};

crates/editor/src/git/blame.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use gpui::{Model, ModelContext, Subscription, Task};
1010
use http_client::HttpClient;
1111
use language::{markdown, Bias, Buffer, BufferSnapshot, Edit, LanguageRegistry, ParsedMarkdown};
1212
use multi_buffer::MultiBufferRow;
13-
use project::{Item, Project};
13+
use project::{Project, ProjectItem};
1414
use smallvec::SmallVec;
1515
use sum_tree::SumTree;
1616
use url::Url;

crates/editor/src/items.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ use language::{
2222
use lsp::DiagnosticSeverity;
2323
use multi_buffer::AnchorRangeExt;
2424
use project::{
25-
lsp_store::FormatTrigger, project_settings::ProjectSettings, search::SearchQuery, Item as _,
26-
Project, ProjectPath,
25+
lsp_store::FormatTrigger, project_settings::ProjectSettings, search::SearchQuery, Project,
26+
ProjectItem as _, ProjectPath,
2727
};
2828
use rpc::proto::{self, update_view, PeerId};
2929
use settings::Settings;
@@ -665,7 +665,7 @@ impl Item for Editor {
665665
fn for_each_project_item(
666666
&self,
667667
cx: &AppContext,
668-
f: &mut dyn FnMut(EntityId, &dyn project::Item),
668+
f: &mut dyn FnMut(EntityId, &dyn project::ProjectItem),
669669
) {
670670
self.buffer
671671
.read(cx)

crates/image_viewer/src/image_viewer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ impl Item for ImageView {
7878
fn for_each_project_item(
7979
&self,
8080
cx: &AppContext,
81-
f: &mut dyn FnMut(gpui::EntityId, &dyn project::Item),
81+
f: &mut dyn FnMut(gpui::EntityId, &dyn project::ProjectItem),
8282
) {
8383
f(self.image_item.entity_id(), self.image_item.read(cx))
8484
}

crates/outline_panel/src/outline_panel.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use language::{BufferId, BufferSnapshot, OffsetRangeExt, OutlineItem};
3636
use menu::{Cancel, SelectFirst, SelectLast, SelectNext, SelectPrev};
3737

3838
use outline_panel_settings::{OutlinePanelDockPosition, OutlinePanelSettings, ShowIndentGuides};
39-
use project::{File, Fs, Item, Project};
39+
use project::{File, Fs, Project, ProjectItem};
4040
use search::{BufferSearchBar, ProjectSearchView};
4141
use serde::{Deserialize, Serialize};
4242
use settings::{Settings, SettingsStore};

crates/project/src/buffer_store.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::{
22
search::SearchQuery,
33
worktree_store::{WorktreeStore, WorktreeStoreEvent},
4-
Item, ProjectPath,
4+
ProjectItem as _, ProjectPath,
55
};
66
use ::git::{parse_git_remote_url, BuildPermalinkParams, GitHostingProviderRegistry};
77
use anyhow::{anyhow, Context as _, Result};

crates/project/src/image_store.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{
22
worktree_store::{WorktreeStore, WorktreeStoreEvent},
3-
Project, ProjectEntryId, ProjectPath,
3+
Project, ProjectEntryId, ProjectItem, ProjectPath,
44
};
55
use anyhow::{Context as _, Result};
66
use collections::{hash_map, HashMap, HashSet};
@@ -114,7 +114,7 @@ impl ImageItem {
114114
}
115115
}
116116

117-
impl crate::Item for ImageItem {
117+
impl ProjectItem for ImageItem {
118118
fn try_open(
119119
project: &Model<Project>,
120120
path: &ProjectPath,
@@ -151,6 +151,10 @@ impl crate::Item for ImageItem {
151151
fn project_path(&self, cx: &AppContext) -> Option<ProjectPath> {
152152
Some(self.project_path(cx).clone())
153153
}
154+
155+
fn is_dirty(&self) -> bool {
156+
false
157+
}
154158
}
155159

156160
trait ImageStoreImpl {

crates/project/src/lsp_store.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::{
1010
toolchain_store::{EmptyToolchainStore, ToolchainStoreEvent},
1111
worktree_store::{WorktreeStore, WorktreeStoreEvent},
1212
yarn::YarnPathStore,
13-
CodeAction, Completion, CoreCompletion, Hover, InlayHint, Item as _, ProjectPath,
13+
CodeAction, Completion, CoreCompletion, Hover, InlayHint, ProjectItem as _, ProjectPath,
1414
ProjectTransaction, ResolveState, Symbol, ToolchainStore,
1515
};
1616
use anyhow::{anyhow, Context as _, Result};

crates/project/src/project.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ const MAX_PROJECT_SEARCH_HISTORY_SIZE: usize = 500;
111111
const MAX_SEARCH_RESULT_FILES: usize = 5_000;
112112
const MAX_SEARCH_RESULT_RANGES: usize = 10_000;
113113

114-
pub trait Item {
114+
pub trait ProjectItem {
115115
fn try_open(
116116
project: &Model<Project>,
117117
path: &ProjectPath,
@@ -121,6 +121,7 @@ pub trait Item {
121121
Self: Sized;
122122
fn entry_id(&self, cx: &AppContext) -> Option<ProjectEntryId>;
123123
fn project_path(&self, cx: &AppContext) -> Option<ProjectPath>;
124+
fn is_dirty(&self) -> bool;
124125
}
125126

126127
#[derive(Clone)]
@@ -4354,7 +4355,7 @@ impl ResolvedPath {
43544355
}
43554356
}
43564357

4357-
impl Item for Buffer {
4358+
impl ProjectItem for Buffer {
43584359
fn try_open(
43594360
project: &Model<Project>,
43604361
path: &ProjectPath,
@@ -4373,6 +4374,10 @@ impl Item for Buffer {
43734374
path: file.path().clone(),
43744375
})
43754376
}
4377+
4378+
fn is_dirty(&self) -> bool {
4379+
self.is_dirty()
4380+
}
43764381
}
43774382

43784383
impl Completion {

crates/project_panel/src/project_panel.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7511,7 +7511,7 @@ mod tests {
75117511
path: ProjectPath,
75127512
}
75137513

7514-
impl project::Item for TestProjectItem {
7514+
impl project::ProjectItem for TestProjectItem {
75157515
fn try_open(
75167516
_project: &Model<Project>,
75177517
path: &ProjectPath,
@@ -7528,6 +7528,10 @@ mod tests {
75287528
fn project_path(&self, _: &AppContext) -> Option<ProjectPath> {
75297529
Some(self.path.clone())
75307530
}
7531+
7532+
fn is_dirty(&self) -> bool {
7533+
false
7534+
}
75317535
}
75327536

75337537
impl ProjectItem for TestProjectItemView {

crates/repl/src/notebook/notebook_ui.rs

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -158,16 +158,6 @@ impl NotebookEditor {
158158
})
159159
}
160160

161-
fn is_dirty(&self, cx: &AppContext) -> bool {
162-
self.cell_map.values().any(|cell| {
163-
if let Cell::Code(code_cell) = cell {
164-
code_cell.read(cx).is_dirty(cx)
165-
} else {
166-
false
167-
}
168-
})
169-
}
170-
171161
fn clear_outputs(&mut self, cx: &mut ViewContext<Self>) {
172162
for cell in self.cell_map.values() {
173163
if let Cell::Code(code_cell) = cell {
@@ -500,7 +490,7 @@ pub struct NotebookItem {
500490
id: ProjectEntryId,
501491
}
502492

503-
impl project::Item for NotebookItem {
493+
impl project::ProjectItem for NotebookItem {
504494
fn try_open(
505495
project: &Model<Project>,
506496
path: &ProjectPath,
@@ -561,6 +551,10 @@ impl project::Item for NotebookItem {
561551
fn project_path(&self, _: &AppContext) -> Option<ProjectPath> {
562552
Some(self.project_path.clone())
563553
}
554+
555+
fn is_dirty(&self) -> bool {
556+
false
557+
}
564558
}
565559

566560
impl NotebookItem {
@@ -656,7 +650,7 @@ impl Item for NotebookEditor {
656650
fn for_each_project_item(
657651
&self,
658652
cx: &AppContext,
659-
f: &mut dyn FnMut(gpui::EntityId, &dyn project::Item),
653+
f: &mut dyn FnMut(gpui::EntityId, &dyn project::ProjectItem),
660654
) {
661655
f(self.notebook_item.entity_id(), self.notebook_item.read(cx))
662656
}
@@ -734,8 +728,13 @@ impl Item for NotebookEditor {
734728
}
735729

736730
fn is_dirty(&self, cx: &AppContext) -> bool {
737-
// self.is_dirty(cx) TODO
738-
false
731+
self.cell_map.values().any(|cell| {
732+
if let Cell::Code(code_cell) = cell {
733+
code_cell.read(cx).is_dirty(cx)
734+
} else {
735+
false
736+
}
737+
})
739738
}
740739
}
741740

crates/repl/src/repl_editor.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use anyhow::{Context, Result};
77
use editor::Editor;
88
use gpui::{prelude::*, Entity, View, WeakView, WindowContext};
99
use language::{BufferSnapshot, Language, LanguageName, Point};
10-
use project::{Item as _, WorktreeId};
10+
use project::{ProjectItem as _, WorktreeId};
1111

1212
use crate::repl_store::ReplStore;
1313
use crate::session::SessionEvent;

crates/repl/src/repl_sessions_ui.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use gpui::{
33
actions, prelude::*, AnyElement, AppContext, EventEmitter, FocusHandle, FocusableView,
44
Subscription, View,
55
};
6-
use project::Item as _;
6+
use project::ProjectItem as _;
77
use ui::{prelude::*, ButtonLike, ElevationIndex, KeyBinding};
88
use util::ResultExt as _;
99
use workspace::item::ItemEvent;

crates/search/src/project_search.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,7 @@ impl Item for ProjectSearchView {
449449
fn for_each_project_item(
450450
&self,
451451
cx: &AppContext,
452-
f: &mut dyn FnMut(EntityId, &dyn project::Item),
452+
f: &mut dyn FnMut(EntityId, &dyn project::ProjectItem),
453453
) {
454454
self.results_editor.for_each_project_item(cx, f)
455455
}

crates/workspace/src/item.rs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ pub trait Item: FocusableView + EventEmitter<Self::Event> {
208208
fn for_each_project_item(
209209
&self,
210210
_: &AppContext,
211-
_: &mut dyn FnMut(EntityId, &dyn project::Item),
211+
_: &mut dyn FnMut(EntityId, &dyn project::ProjectItem),
212212
) {
213213
}
214214
fn is_singleton(&self, _cx: &AppContext) -> bool {
@@ -386,7 +386,7 @@ pub trait ItemHandle: 'static + Send {
386386
fn for_each_project_item(
387387
&self,
388388
_: &AppContext,
389-
_: &mut dyn FnMut(EntityId, &dyn project::Item),
389+
_: &mut dyn FnMut(EntityId, &dyn project::ProjectItem),
390390
);
391391
fn is_singleton(&self, cx: &AppContext) -> bool;
392392
fn boxed_clone(&self) -> Box<dyn ItemHandle>;
@@ -563,7 +563,7 @@ impl<T: Item> ItemHandle for View<T> {
563563
fn for_each_project_item(
564564
&self,
565565
cx: &AppContext,
566-
f: &mut dyn FnMut(EntityId, &dyn project::Item),
566+
f: &mut dyn FnMut(EntityId, &dyn project::ProjectItem),
567567
) {
568568
self.read(cx).for_each_project_item(cx, f)
569569
}
@@ -891,7 +891,7 @@ impl<T: Item> WeakItemHandle for WeakView<T> {
891891
}
892892

893893
pub trait ProjectItem: Item {
894-
type Item: project::Item;
894+
type Item: project::ProjectItem;
895895

896896
fn for_project_item(
897897
project: Model<Project>,
@@ -1045,6 +1045,7 @@ pub mod test {
10451045
pub struct TestProjectItem {
10461046
pub entry_id: Option<ProjectEntryId>,
10471047
pub project_path: Option<ProjectPath>,
1048+
pub is_dirty: bool,
10481049
}
10491050

10501051
pub struct TestItem {
@@ -1065,22 +1066,25 @@ pub mod test {
10651066
focus_handle: gpui::FocusHandle,
10661067
}
10671068

1068-
impl project::Item for TestProjectItem {
1069+
impl project::ProjectItem for TestProjectItem {
10691070
fn try_open(
10701071
_project: &Model<Project>,
10711072
_path: &ProjectPath,
10721073
_cx: &mut AppContext,
10731074
) -> Option<Task<gpui::Result<Model<Self>>>> {
10741075
None
10751076
}
1076-
10771077
fn entry_id(&self, _: &AppContext) -> Option<ProjectEntryId> {
10781078
self.entry_id
10791079
}
10801080

10811081
fn project_path(&self, _: &AppContext) -> Option<ProjectPath> {
10821082
self.project_path.clone()
10831083
}
1084+
1085+
fn is_dirty(&self) -> bool {
1086+
self.is_dirty
1087+
}
10841088
}
10851089

10861090
pub enum TestItemEvent {
@@ -1097,13 +1101,15 @@ pub mod test {
10971101
cx.new_model(|_| Self {
10981102
entry_id,
10991103
project_path,
1104+
is_dirty: false,
11001105
})
11011106
}
11021107

11031108
pub fn new_untitled(cx: &mut AppContext) -> Model<Self> {
11041109
cx.new_model(|_| Self {
11051110
project_path: None,
11061111
entry_id: None,
1112+
is_dirty: false,
11071113
})
11081114
}
11091115
}
@@ -1225,7 +1231,7 @@ pub mod test {
12251231
fn for_each_project_item(
12261232
&self,
12271233
cx: &AppContext,
1228-
f: &mut dyn FnMut(EntityId, &dyn project::Item),
1234+
f: &mut dyn FnMut(EntityId, &dyn project::ProjectItem),
12291235
) {
12301236
self.project_items
12311237
.iter()

0 commit comments

Comments
 (0)