Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

debug: fix tasks get stuck when restoring a PTY #200273

Merged
merged 1 commit into from
Dec 7, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 8 additions & 7 deletions src/vs/workbench/contrib/debug/browser/debugTaskRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { Markers } from 'vs/workbench/contrib/markers/common/markers';
import { ITaskService, ITaskSummary } from 'vs/workbench/contrib/tasks/common/taskService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IWorkspaceFolder, IWorkspace } from 'vs/platform/workspace/common/workspace';
import { ITaskEvent, TaskEventKind, ITaskIdentifier } from 'vs/workbench/contrib/tasks/common/tasks';
import { ITaskEvent, TaskEventKind, ITaskIdentifier, Task } from 'vs/workbench/contrib/tasks/common/tasks';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { IMarkerService, MarkerSeverity } from 'vs/platform/markers/common/markers';
import { IDebugConfiguration } from 'vs/workbench/contrib/debug/common/debug';
Expand Down Expand Up @@ -200,32 +200,33 @@ export class DebugTaskRunner {

// If a task is missing the problem matcher the promise will never complete, so we need to have a workaround #35340
let taskStarted = false;
const taskKey = task.getMapKey();
const getTaskKey = (t: Task) => t.getKey() ?? t.getMapKey();
const taskKey = getTaskKey(task);
const inactivePromise: Promise<ITaskSummary | null> = new Promise((c) => once(e => {
// When a task isBackground it will go inactive when it is safe to launch.
// But when a background task is terminated by the user, it will also fire an inactive event.
// This means that we will not get to see the real exit code from running the task (undefined when terminated by the user).
// Catch the ProcessEnded event here, which occurs before inactive, and capture the exit code to prevent this.
return (e.kind === TaskEventKind.Inactive
|| (e.kind === TaskEventKind.ProcessEnded && e.exitCode === undefined))
&& e.__task?.getMapKey() === taskKey;
&& getTaskKey(e.__task) === taskKey;
}, this.taskService.onDidStateChange)(e => {
taskStarted = true;
c(e.kind === TaskEventKind.ProcessEnded ? { exitCode: e.exitCode } : null);
}));

const promise: Promise<ITaskSummary | null> = this.taskService.getActiveTasks().then(async (tasks): Promise<ITaskSummary | null> => {
if (tasks.find(t => t.getMapKey() === taskKey)) {
if (tasks.find(t => getTaskKey(t) === taskKey)) {
// Check that the task isn't busy and if it is, wait for it
const busyTasks = await this.taskService.getBusyTasks();
if (busyTasks.find(t => t.getMapKey() === taskKey)) {
if (busyTasks.find(t => getTaskKey(t) === taskKey)) {
taskStarted = true;
return inactivePromise;
}
// task is already running and isn't busy - nothing to do.
return Promise.resolve(null);
}
once(e => ((e.kind === TaskEventKind.Active) || (e.kind === TaskEventKind.DependsOnStarted)) && e.__task?.getMapKey() === taskKey, this.taskService.onDidStateChange)(() => {
once(e => ((e.kind === TaskEventKind.Active) || (e.kind === TaskEventKind.DependsOnStarted)) && getTaskKey(e.__task) === taskKey, this.taskService.onDidStateChange)(() => {
// Task is active, so everything seems to be fine, no need to prompt after 10 seconds
// Use case being a slow running task should not be prompted even though it takes more than 10 seconds
taskStarted = true;
Expand All @@ -239,7 +240,7 @@ export class DebugTaskRunner {
});

return new Promise((c, e) => {
const waitForInput = new Promise<void>(resolve => once(e => (e.kind === TaskEventKind.AcquiredInput) && e.__task?.getMapKey() === taskKey, this.taskService.onDidStateChange)(() => {
const waitForInput = new Promise<void>(resolve => once(e => (e.kind === TaskEventKind.AcquiredInput) && getTaskKey(e.__task) === taskKey, this.taskService.onDidStateChange)(() => {
resolve();
}));

Expand Down