Skip to content

Commit

Permalink
Add terminal statuses for tasks
Browse files Browse the repository at this point in the history
Part of #121659
  • Loading branch information
alexr00 committed May 11, 2021
1 parent 50d78f1 commit 2a39f1f
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1635,6 +1635,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
this.contextService, this.environmentService,
AbstractTaskService.OutputChannelId, this.fileService, this.terminalProfileResolverService,
this.pathService, this.viewDescriptorService, this.logService, this.configurationService,
this,
(workspaceFolder: IWorkspaceFolder | undefined) => {
if (workspaceFolder) {
return this.getTaskSystemInfo(workspaceFolder.uri.scheme);
Expand Down
95 changes: 95 additions & 0 deletions src/vs/workbench/contrib/tasks/browser/taskTerminalStatus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { Codicon } from 'vs/base/common/codicons';
import { Disposable } from 'vs/base/common/lifecycle';
import Severity from 'vs/base/common/severity';
import { AbstractProblemCollector } from 'vs/workbench/contrib/tasks/common/problemCollectors';
import { TaskEvent, TaskEventKind } from 'vs/workbench/contrib/tasks/common/tasks';
import { ITaskService, Task } from 'vs/workbench/contrib/tasks/common/taskService';
import { ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal';
import { ITerminalStatus } from 'vs/workbench/contrib/terminal/browser/terminalStatusList';

interface TerminalData {
terminal: ITerminalInstance;
status: ITerminalStatus;
problemMatcher: AbstractProblemCollector;
}

const TASK_TERMINAL_STATUS_ID = 'task_terminal_status';
const loadingSpin = Codicon.loading;
loadingSpin.classNamesArray.push('codicon-spin');
const ACTIVE_TASK_STATUS: ITerminalStatus = { id: TASK_TERMINAL_STATUS_ID, icon: loadingSpin, severity: Severity.Info };
const INACTIVE_TASK_STATUS: ITerminalStatus = { id: TASK_TERMINAL_STATUS_ID, icon: Codicon.play, severity: Severity.Info };
const SUCCEEDED_TASK_STATUS: ITerminalStatus = { id: TASK_TERMINAL_STATUS_ID, icon: Codicon.check, severity: Severity.Info };
const FAILED_TASK_STATUS: ITerminalStatus = { id: TASK_TERMINAL_STATUS_ID, icon: Codicon.error, severity: Severity.Warning };

export class TaskTerminalStatus extends Disposable {
private terminalMap: Map<Task, TerminalData> = new Map();

constructor(taskService: ITaskService) {
super();
this._register(taskService.onDidStateChange((event) => {
switch (event.kind) {
case TaskEventKind.Start:
case TaskEventKind.Active: this.eventActive(event); break;
case TaskEventKind.Inactive: this.eventInactive(event); break;
case TaskEventKind.ProcessEnded: this.eventEnd(event); break;
}
}));
}

addTerminal(task: Task, terminal: ITerminalInstance, problemMatcher: AbstractProblemCollector) {
const status: ITerminalStatus = { id: TASK_TERMINAL_STATUS_ID, severity: Severity.Info };
terminal.statusList.add(status);
this.terminalMap.set(task, { terminal, status, problemMatcher });
}

private terminalFromEvent(event: TaskEvent): TerminalData | undefined {
if (!event.__task || !this.terminalMap.get(event.__task)) {
return undefined;
}

return this.terminalMap.get(event.__task);
}

private eventEnd(event: TaskEvent) {
const terminalData = this.terminalFromEvent(event);
if (!terminalData) {
return;
}

this.terminalMap.delete(event.__task!);

terminalData.terminal.statusList.remove(terminalData.status);
if ((event.exitCode === 0) && (terminalData.problemMatcher.numberOfMatches === 0)) {
terminalData.terminal.statusList.add(SUCCEEDED_TASK_STATUS);
} else {
terminalData.terminal.statusList.add(FAILED_TASK_STATUS);
}
}

private eventInactive(event: TaskEvent) {
const terminalData = this.terminalFromEvent(event);
if (!terminalData) {
return;
}
terminalData.terminal.statusList.remove(terminalData.status);
if (terminalData.problemMatcher.numberOfMatches === 0) {
terminalData.terminal.statusList.add(INACTIVE_TASK_STATUS);
} else {
terminalData.terminal.statusList.add(FAILED_TASK_STATUS);
}
}

private eventActive(event: TaskEvent) {
const terminalData = this.terminalFromEvent(event);
if (!terminalData) {
return;
}
terminalData.terminal.statusList.remove(terminalData.status);
terminalData.terminal.statusList.add(ACTIVE_TASK_STATUS);
}
}
12 changes: 10 additions & 2 deletions src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { IStringDictionary, values } from 'vs/base/common/collections';
import { LinkedMap, Touch } from 'vs/base/common/map';
import Severity from 'vs/base/common/severity';
import { Event, Emitter } from 'vs/base/common/event';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { isUNC } from 'vs/base/common/extpath';

import { IFileService } from 'vs/platform/files/common/files';
Expand Down Expand Up @@ -49,6 +49,8 @@ import { ILogService } from 'vs/platform/log/common/log';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IShellLaunchConfig } from 'vs/platform/terminal/common/terminal';
import { TerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy';
import { TaskTerminalStatus } from 'vs/workbench/contrib/tasks/browser/taskTerminalStatus';
import { ITaskService } from 'vs/workbench/contrib/tasks/common/taskService';

interface TerminalData {
terminal: ITerminalInstance;
Expand Down Expand Up @@ -141,7 +143,7 @@ export class VerifiedTask {
}
}

export class TerminalTaskSystem implements ITaskSystem {
export class TerminalTaskSystem extends Disposable implements ITaskSystem {

public static TelemetryEventName: string = 'taskService';

Expand Down Expand Up @@ -196,6 +198,7 @@ export class TerminalTaskSystem implements ITaskSystem {
private isRerun: boolean = false;
private previousPanelId: string | undefined;
private previousTerminalInstance: ITerminalInstance | undefined;
private terminalStatusManager: TaskTerminalStatus;

private readonly _onDidStateChange: Emitter<TaskEvent>;

Expand All @@ -216,8 +219,10 @@ export class TerminalTaskSystem implements ITaskSystem {
private viewDescriptorService: IViewDescriptorService,
private logService: ILogService,
private configurationService: IConfigurationService,
taskService: ITaskService,
taskSystemInfoResolver: TaskSystemInfoResolver,
) {
super();

this.activeTasks = Object.create(null);
this.instances = Object.create(null);
Expand All @@ -228,6 +233,7 @@ export class TerminalTaskSystem implements ITaskSystem {

this._onDidStateChange = new Emitter();
this.taskSystemInfoResolver = taskSystemInfoResolver;
this._register(this.terminalStatusManager = new TaskTerminalStatus(taskService));
}

public get onDidStateChange(): Event<TaskEvent> {
Expand Down Expand Up @@ -781,6 +787,7 @@ export class TerminalTaskSystem implements ITaskSystem {
if (!terminal) {
return Promise.reject(new Error(`Failed to create terminal for task ${task._label}`));
}
this.terminalStatusManager.addTerminal(task, terminal, watchingProblemMatcher);

let processStartedSignaled = false;
terminal.processReady.then(() => {
Expand Down Expand Up @@ -883,6 +890,7 @@ export class TerminalTaskSystem implements ITaskSystem {
this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.Active, task));
let problemMatchers = await this.resolveMatchers(resolver, task.configurationProperties.problemMatchers);
let startStopProblemMatcher = new StartStopProblemCollector(problemMatchers, this.markerService, this.modelService, ProblemHandlingStrategy.Clean, this.fileService);
this.terminalStatusManager.addTerminal(task, terminal, startStopProblemMatcher);
let skipLine: boolean = (!!task.command.presentation && task.command.presentation.echo);
const onData = terminal.onLineData((line) => {
if (skipLine) {
Expand Down

0 comments on commit 2a39f1f

Please sign in to comment.