Fix tasks not being stopped on reruns (#29786)

Follow-up of https://github.com/zed-industries/zed/pull/28993

* Tone down tasks' cancellation logging
* Fix task terminals' leak, disallowing to fully cancel the task by
dropping the terminal off the pane:

f619d5f02a/crates/terminal_view/src/terminal_panel.rs (L1464-L1471)

Release Notes:

- Fixed tasks not being stopped on reruns
This commit is contained in:
Kirill Bulatov 2025-05-02 14:45:43 +03:00 committed by GitHub
parent 460ac96df4
commit e14d078f8a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 69 additions and 41 deletions

View file

@ -483,7 +483,7 @@ impl TerminalPanel {
task: &SpawnInTerminal,
window: &mut Window,
cx: &mut Context<Self>,
) -> Task<Result<Entity<Terminal>>> {
) -> Task<Result<WeakEntity<Terminal>>> {
let Ok(is_local) = self
.workspace
.update(cx, |workspace, cx| workspace.project().read(cx).is_local())
@ -552,12 +552,12 @@ impl TerminalPanel {
cx.spawn(async move |_, _| rx.await?)
}
pub fn spawn_in_new_terminal(
fn spawn_in_new_terminal(
&mut self,
spawn_task: SpawnInTerminal,
window: &mut Window,
cx: &mut Context<Self>,
) -> Task<Result<Entity<Terminal>>> {
) -> Task<Result<WeakEntity<Terminal>>> {
let reveal = spawn_task.reveal;
let reveal_target = spawn_task.reveal_target;
let kind = TerminalKind::Task(spawn_task);
@ -652,7 +652,7 @@ impl TerminalPanel {
kind: TerminalKind,
window: &mut Window,
cx: &mut Context<Workspace>,
) -> Task<Result<Entity<Terminal>>> {
) -> Task<Result<WeakEntity<Terminal>>> {
if !is_enabled_in_workspace(workspace, cx) {
return Task::ready(Err(anyhow!(
"terminal not yet supported for remote projects"
@ -680,7 +680,7 @@ impl TerminalPanel {
});
workspace.add_item_to_active_pane(Box::new(terminal_view), None, true, window, cx);
})?;
Ok(terminal)
Ok(terminal.downgrade())
})
}
@ -690,7 +690,7 @@ impl TerminalPanel {
reveal_strategy: RevealStrategy,
window: &mut Window,
cx: &mut Context<Self>,
) -> Task<Result<Entity<Terminal>>> {
) -> Task<Result<WeakEntity<Terminal>>> {
let workspace = self.workspace.clone();
cx.spawn_in(window, async move |terminal_panel, cx| {
if workspace.update(cx, |workspace, cx| !is_enabled_in_workspace(workspace, cx))? {
@ -735,11 +735,12 @@ impl TerminalPanel {
pane.add_item(terminal_view, true, focus, None, window, cx);
});
Ok(terminal)
Ok(terminal.downgrade())
})?;
terminal_panel.update(cx, |this, cx| {
this.pending_terminals_to_add = this.pending_terminals_to_add.saturating_sub(1);
this.serialize(cx)
terminal_panel.update(cx, |terminal_panel, cx| {
terminal_panel.pending_terminals_to_add =
terminal_panel.pending_terminals_to_add.saturating_sub(1);
terminal_panel.serialize(cx)
})?;
result
})
@ -802,7 +803,7 @@ impl TerminalPanel {
terminal_to_replace: Entity<TerminalView>,
window: &mut Window,
cx: &mut Context<Self>,
) -> Task<Result<Entity<Terminal>>> {
) -> Task<Result<WeakEntity<Terminal>>> {
let reveal = spawn_task.reveal;
let reveal_target = spawn_task.reveal_target;
let window_handle = window.window_handle();
@ -884,7 +885,7 @@ impl TerminalPanel {
RevealStrategy::Never => {}
}
Ok(new_terminal)
Ok(new_terminal.downgrade())
})
}
@ -1458,22 +1459,25 @@ impl workspace::TerminalProvider for TerminalProvider {
task: SpawnInTerminal,
window: &mut Window,
cx: &mut App,
) -> Task<Result<ExitStatus>> {
let this = self.0.clone();
) -> Task<Option<Result<ExitStatus>>> {
let terminal_panel = self.0.clone();
window.spawn(cx, async move |cx| {
let terminal = this
let terminal = terminal_panel
.update_in(cx, |terminal_panel, window, cx| {
terminal_panel.spawn_task(&task, window, cx)
})?
.await?;
let Some(exit_code) = terminal
.read_with(cx, |terminal, cx| terminal.wait_for_completed_task(cx))?
.await
else {
return Err(anyhow!("Task cancelled"));
};
Ok(exit_code)
})
.ok()?
.await;
match terminal {
Ok(terminal) => {
let exit_status = terminal
.read_with(cx, |terminal, cx| terminal.wait_for_completed_task(cx))
.ok()?
.await?;
Some(Ok(exit_status))
}
Err(e) => Some(Err(e)),
}
})
}
}