in src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts [513:754]
private async executeInTerminal(task: CustomTask | ContributedTask, trigger: string, resolver: VariableResolver, workspaceFolder: IWorkspaceFolder): Promise<ITaskSummary> {
let terminal: ITerminalInstance | undefined = undefined;
let executedCommand: string | undefined = undefined;
let error: TaskError | undefined = undefined;
let promise: Promise<ITaskSummary> | undefined = undefined;
if (task.configurationProperties.isBackground) {
const problemMatchers = this.resolveMatchers(resolver, task.configurationProperties.problemMatchers);
let watchingProblemMatcher = new WatchingProblemCollector(problemMatchers, this.markerService, this.modelService, this.fileService);
const toDispose = new DisposableStore();
let eventCounter: number = 0;
toDispose.add(watchingProblemMatcher.onDidStateChange((event) => {
if (event.kind === ProblemCollectorEventKind.BackgroundProcessingBegins) {
eventCounter++;
this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.Active, task));
} else if (event.kind === ProblemCollectorEventKind.BackgroundProcessingEnds) {
eventCounter--;
this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.Inactive, task));
if (eventCounter === 0) {
if ((watchingProblemMatcher.numberOfMatches > 0) && watchingProblemMatcher.maxMarkerSeverity &&
(watchingProblemMatcher.maxMarkerSeverity >= MarkerSeverity.Error)) {
let reveal = task.command.presentation!.reveal;
let revealProblems = task.command.presentation!.revealProblems;
if (revealProblems === RevealProblemKind.OnProblem) {
this.panelService.openPanel(Constants.MARKERS_PANEL_ID, true);
} else if (reveal === RevealKind.Silent) {
this.terminalService.setActiveInstance(terminal!);
this.terminalService.showPanel(false);
}
}
}
}
}));
watchingProblemMatcher.aboutToStart();
let delayer: Async.Delayer<any> | undefined = undefined;
[terminal, executedCommand, error] = await this.createTerminal(task, resolver, workspaceFolder);
if (error) {
return Promise.reject(new Error((<TaskError>error).message));
}
if (!terminal) {
return Promise.reject(new Error(`Failed to create terminal for task ${task._label}`));
}
let processStartedSignaled = false;
terminal.processReady.then(() => {
if (!processStartedSignaled) {
if (task.command.runtime !== RuntimeType.CustomExecution) {
this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.ProcessStarted, task, terminal!.processId!));
}
processStartedSignaled = true;
}
}, (_error) => {
// The process never got ready. Need to think how to handle this.
});
this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.Start, task, terminal.id));
const registeredLinkMatchers = this.registerLinkMatchers(terminal, problemMatchers);
const onData = terminal.onLineData((line) => {
watchingProblemMatcher.processLine(line);
if (!delayer) {
delayer = new Async.Delayer(3000);
}
delayer.trigger(() => {
watchingProblemMatcher.forceDelivery();
delayer = undefined;
});
});
promise = new Promise<ITaskSummary>((resolve, reject) => {
const onExit = terminal!.onExit((exitCode) => {
onData.dispose();
onExit.dispose();
let key = task.getMapKey();
delete this.activeTasks[key];
this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.Changed));
if (exitCode !== undefined) {
// Only keep a reference to the terminal if it is not being disposed.
switch (task.command.presentation!.panel) {
case PanelKind.Dedicated:
this.sameTaskTerminals[key] = terminal!.id.toString();
break;
case PanelKind.Shared:
this.idleTaskTerminals.set(key, terminal!.id.toString(), Touch.AsOld);
break;
}
}
let reveal = task.command.presentation!.reveal;
if ((reveal === RevealKind.Silent) && ((exitCode !== 0) || (watchingProblemMatcher.numberOfMatches > 0) && watchingProblemMatcher.maxMarkerSeverity &&
(watchingProblemMatcher.maxMarkerSeverity >= MarkerSeverity.Error))) {
this.terminalService.setActiveInstance(terminal!);
this.terminalService.showPanel(false);
}
watchingProblemMatcher.done();
watchingProblemMatcher.dispose();
registeredLinkMatchers.forEach(handle => terminal!.deregisterLinkMatcher(handle));
if (!processStartedSignaled) {
this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.ProcessStarted, task, terminal!.processId!));
processStartedSignaled = true;
}
if (task.command.runtime !== RuntimeType.CustomExecution) {
this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.ProcessEnded, task, exitCode));
}
for (let i = 0; i < eventCounter; i++) {
let event = TaskEvent.create(TaskEventKind.Inactive, task);
this._onDidStateChange.fire(event);
}
eventCounter = 0;
this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.End, task));
toDispose.dispose();
resolve({ exitCode });
});
});
} else {
[terminal, executedCommand, error] = await this.createTerminal(task, resolver, workspaceFolder);
if (error) {
return Promise.reject(new Error((<TaskError>error).message));
}
if (!terminal) {
return Promise.reject(new Error(`Failed to create terminal for task ${task._label}`));
}
let processStartedSignaled = false;
terminal.processReady.then(() => {
if (!processStartedSignaled) {
if (task.command.runtime !== RuntimeType.CustomExecution) {
this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.ProcessStarted, task, terminal!.processId!));
}
processStartedSignaled = true;
}
}, (_error) => {
// The process never got ready. Need to think how to handle this.
});
this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.Start, task, terminal.id));
this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.Active, task));
let problemMatchers = this.resolveMatchers(resolver, task.configurationProperties.problemMatchers);
let startStopProblemMatcher = new StartStopProblemCollector(problemMatchers, this.markerService, this.modelService, ProblemHandlingStrategy.Clean, this.fileService);
const registeredLinkMatchers = this.registerLinkMatchers(terminal, problemMatchers);
const onData = terminal.onLineData((line) => {
startStopProblemMatcher.processLine(line);
});
promise = new Promise<ITaskSummary>((resolve, reject) => {
const onExit = terminal!.onExit((exitCode) => {
onData.dispose();
onExit.dispose();
let key = task.getMapKey();
delete this.activeTasks[key];
this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.Changed));
if (exitCode !== undefined) {
// Only keep a reference to the terminal if it is not being disposed.
switch (task.command.presentation!.panel) {
case PanelKind.Dedicated:
this.sameTaskTerminals[key] = terminal!.id.toString();
break;
case PanelKind.Shared:
this.idleTaskTerminals.set(key, terminal!.id.toString(), Touch.AsOld);
break;
}
}
let reveal = task.command.presentation!.reveal;
let revealProblems = task.command.presentation!.revealProblems;
let revealProblemPanel = terminal && (revealProblems === RevealProblemKind.OnProblem) && (startStopProblemMatcher.numberOfMatches > 0);
if (revealProblemPanel) {
this.panelService.openPanel(Constants.MARKERS_PANEL_ID);
} else if (terminal && (reveal === RevealKind.Silent) && ((exitCode !== 0) || (startStopProblemMatcher.numberOfMatches > 0) && startStopProblemMatcher.maxMarkerSeverity &&
(startStopProblemMatcher.maxMarkerSeverity >= MarkerSeverity.Error))) {
this.terminalService.setActiveInstance(terminal);
this.terminalService.showPanel(false);
}
startStopProblemMatcher.done();
startStopProblemMatcher.dispose();
registeredLinkMatchers.forEach(handle => {
if (terminal) {
terminal.deregisterLinkMatcher(handle);
}
});
if (!processStartedSignaled && terminal) {
this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.ProcessStarted, task, terminal.processId!));
processStartedSignaled = true;
}
if (task.command.runtime !== RuntimeType.CustomExecution) {
this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.ProcessEnded, task, exitCode));
}
this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.Inactive, task));
this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.End, task));
resolve({ exitCode });
});
});
}
let showProblemPanel = task.command.presentation && (task.command.presentation.revealProblems === RevealProblemKind.Always);
if (showProblemPanel) {
this.panelService.openPanel(Constants.MARKERS_PANEL_ID);
} else if (task.command.presentation && (task.command.presentation.reveal === RevealKind.Always)) {
this.terminalService.setActiveInstance(terminal);
this.terminalService.showPanel(task.command.presentation.focus);
}
this.activeTasks[task.getMapKey()] = { terminal, task, promise };
this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.Changed));
return promise.then((summary) => {
try {
let telemetryEvent: TelemetryEvent = {
trigger: trigger,
runner: 'terminal',
taskKind: task.getTelemetryKind(),
command: this.getSanitizedCommand(executedCommand!),
success: true,
exitCode: summary.exitCode
};
/* __GDPR__
"taskService" : {
"${include}": [
"${TelemetryEvent}"
]
}
*/
this.telemetryService.publicLog(TerminalTaskSystem.TelemetryEventName, telemetryEvent);
} catch (error) {
}
return summary;
}, (error) => {
try {
let telemetryEvent: TelemetryEvent = {
trigger: trigger,
runner: 'terminal',
taskKind: task.getTelemetryKind(),
command: this.getSanitizedCommand(executedCommand!),
success: false
};
/* __GDPR__
"taskService" : {
"${include}": [
"${TelemetryEvent}"
]
}
*/
this.telemetryService.publicLog(TerminalTaskSystem.TelemetryEventName, telemetryEvent);
} catch (error) {
}
return Promise.reject<ITaskSummary>(error);
});
}