Fix Workspace references being leaked (#17497)

We noticed that the `Workspace` was never released (along with the
`Project` and everything that comes along with that) when closing a
window.

After playing around with the LeakDetector and debugging with
`cx.on_release()` callbacks, we found two culprits: the inline assistant
and the outline panel.

Both held strong references to `View<Workspace>` after PR #16589 and PR
#16845.

This PR changes both references to `WeakView<Workspace>` which fixes the
leak but keeps the behaviour the same.

Release Notes:

- N/A

Co-authored-by: Bennet <bennet@zed.dev>
This commit is contained in:
Thorsten Ball 2024-09-06 15:32:34 +02:00 committed by GitHub
parent e6c1c51b37
commit 54dd40878f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 38 additions and 24 deletions

View file

@ -134,8 +134,11 @@ impl InlineAssistant {
}) })
.detach(); .detach();
let workspace = workspace.clone(); let workspace = workspace.downgrade();
cx.observe_global::<SettingsStore>(move |cx| { cx.observe_global::<SettingsStore>(move |cx| {
let Some(workspace) = workspace.upgrade() else {
return;
};
let Some(terminal_panel) = workspace.read(cx).panel::<TerminalPanel>(cx) else { let Some(terminal_panel) = workspace.read(cx).panel::<TerminalPanel>(cx) else {
return; return;
}; };

View file

@ -91,7 +91,7 @@ pub struct OutlinePanel {
fs: Arc<dyn Fs>, fs: Arc<dyn Fs>,
width: Option<Pixels>, width: Option<Pixels>,
project: Model<Project>, project: Model<Project>,
workspace: View<Workspace>, workspace: WeakView<Workspace>,
active: bool, active: bool,
pinned: bool, pinned: bool,
scroll_handle: UniformListScrollHandle, scroll_handle: UniformListScrollHandle,
@ -607,7 +607,7 @@ impl OutlinePanel {
fn new(workspace: &mut Workspace, cx: &mut ViewContext<Workspace>) -> View<Self> { fn new(workspace: &mut Workspace, cx: &mut ViewContext<Workspace>) -> View<Self> {
let project = workspace.project().clone(); let project = workspace.project().clone();
let workspace_handle = cx.view().clone(); let workspace_handle = cx.view().downgrade();
let outline_panel = cx.new_view(|cx| { let outline_panel = cx.new_view(|cx| {
let filter_editor = cx.new_view(|cx| { let filter_editor = cx.new_view(|cx| {
let mut editor = Editor::single_line(cx); let mut editor = Editor::single_line(cx);
@ -865,7 +865,8 @@ impl OutlinePanel {
}; };
if let Some((offset, anchor)) = scroll_target { if let Some((offset, anchor)) = scroll_target {
self.workspace let activate = self
.workspace
.update(cx, |workspace, cx| match self.active_item() { .update(cx, |workspace, cx| match self.active_item() {
Some(active_item) => { Some(active_item) => {
workspace.activate_item(active_item.as_ref(), true, change_selection, cx) workspace.activate_item(active_item.as_ref(), true, change_selection, cx)
@ -873,6 +874,7 @@ impl OutlinePanel {
None => workspace.activate_item(&active_editor, true, change_selection, cx), None => workspace.activate_item(&active_editor, true, change_selection, cx),
}); });
if activate.is_ok() {
self.select_entry(entry.clone(), true, cx); self.select_entry(entry.clone(), true, cx);
if change_selection { if change_selection {
active_editor.update(cx, |editor, cx| { active_editor.update(cx, |editor, cx| {
@ -891,6 +893,7 @@ impl OutlinePanel {
} }
} }
} }
}
fn select_next(&mut self, _: &SelectNext, cx: &mut ViewContext<Self>) { fn select_next(&mut self, _: &SelectNext, cx: &mut ViewContext<Self>) {
if let Some(entry_to_select) = self.selected_entry().and_then(|selected_entry| { if let Some(entry_to_select) = self.selected_entry().and_then(|selected_entry| {
@ -3316,7 +3319,11 @@ impl OutlinePanel {
let buffer_search = self let buffer_search = self
.active_item() .active_item()
.as_deref() .as_deref()
.and_then(|active_item| self.workspace.read(cx).pane_for(active_item)) .and_then(|active_item| {
self.workspace
.upgrade()
.and_then(|workspace| workspace.read(cx).pane_for(active_item))
})
.and_then(|pane| { .and_then(|pane| {
pane.read(cx) pane.read(cx)
.toolbar() .toolbar()
@ -3567,8 +3574,10 @@ impl OutlinePanel {
) { ) {
self.pinned = !self.pinned; self.pinned = !self.pinned;
if !self.pinned { if !self.pinned {
if let Some((active_item, active_editor)) = if let Some((active_item, active_editor)) = self
workspace_active_editor(self.workspace.read(cx), cx) .workspace
.upgrade()
.and_then(|workspace| workspace_active_editor(workspace.read(cx), cx))
{ {
if self.should_replace_active_item(active_item.as_ref()) { if self.should_replace_active_item(active_item.as_ref()) {
self.replace_active_editor(active_item, active_editor, cx); self.replace_active_editor(active_item, active_editor, cx);
@ -3833,8 +3842,10 @@ impl Panel for OutlinePanel {
let old_active = outline_panel.active; let old_active = outline_panel.active;
outline_panel.active = active; outline_panel.active = active;
if active && old_active != active { if active && old_active != active {
if let Some((active_item, active_editor)) = if let Some((active_item, active_editor)) = outline_panel
workspace_active_editor(outline_panel.workspace.read(cx), cx) .workspace
.upgrade()
.and_then(|workspace| workspace_active_editor(workspace.read(cx), cx))
{ {
if outline_panel.should_replace_active_item(active_item.as_ref()) { if outline_panel.should_replace_active_item(active_item.as_ref()) {
outline_panel.replace_active_editor(active_item, active_editor, cx); outline_panel.replace_active_editor(active_item, active_editor, cx);