提交 a9cb9a7d 编写于 作者: D Dirk Baeumer

First cut of using the terminal to execute tasks

上级 6ecb0393
......@@ -779,7 +779,7 @@ export class DebugService implements debug.IDebugService {
this.lastTaskEvent = null;
});
if (filteredTasks[0].isWatching) {
if (filteredTasks[0].isBackground) {
return new TPromise((c, e) => this.taskService.addOneTimeDisposableListener(TaskServiceEvents.Inactive, () => c(null)));
}
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TPromise, Promise } from 'vs/base/common/winjs.base';
import { TerminateResponse } from 'vs/base/common/processes';
import { IMode } from 'vs/editor/common/modes';
import { EventEmitter } from 'vs/base/common/eventEmitter';
import { ITaskSystem, ITaskSummary, TaskDescription, TelemetryEvent, Triggers, TaskConfiguration, ITaskExecuteResult, TaskExecuteKind } from 'vs/workbench/parts/tasks/common/taskSystem';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IModeService } from 'vs/editor/common/services/modeService';
export interface LanguageServiceTaskConfiguration extends TaskConfiguration {
modes: string[];
}
export class LanguageServiceTaskSystem extends EventEmitter implements ITaskSystem {
public static TelemetryEventName: string = 'taskService';
private configuration: LanguageServiceTaskConfiguration;
private telemetryService: ITelemetryService;
private modeService: IModeService;
constructor(configuration: LanguageServiceTaskConfiguration, telemetryService: ITelemetryService, modeService: IModeService) {
super();
this.configuration = configuration;
this.telemetryService = telemetryService;
this.modeService = modeService;
}
public build(): ITaskExecuteResult {
return this.processMode((mode) => {
return null;
}, 'build', Triggers.shortcut);
}
public rebuild(): ITaskExecuteResult {
return this.processMode((mode) => {
return null;
}, 'rebuild', Triggers.shortcut);
}
public clean(): ITaskExecuteResult {
return this.processMode((mode) => {
return null;
}, 'clean', Triggers.shortcut);
}
public runTest(): ITaskExecuteResult {
return { kind: TaskExecuteKind.Started, promise: TPromise.wrapError<ITaskSummary>('Not implemented yet.') };
}
public run(taskIdentifier: string): ITaskExecuteResult {
return { kind: TaskExecuteKind.Started, promise: TPromise.wrapError<ITaskSummary>('Not implemented yet.') };
}
public isActive(): TPromise<boolean> {
return TPromise.as(false);
}
public isActiveSync(): boolean {
return false;
}
public canAutoTerminate(): boolean {
return false;
}
public terminate(): TPromise<TerminateResponse> {
return TPromise.as({ success: true });
}
public terminateSync(): TerminateResponse {
return { success: true };
}
public tasks(): TPromise<TaskDescription[]> {
let result: TaskDescription[] = [];
return TPromise.as(result);
}
private processMode(fn: (mode: IMode) => Promise, taskName: string, trigger: string): ITaskExecuteResult {
let telemetryEvent: TelemetryEvent = {
trigger: trigger,
command: 'languageService',
success: true
};
return {
kind: TaskExecuteKind.Started, started: {}, promise: Promise.join(this.configuration.modes.map((mode) => {
return this.modeService.getOrCreateMode(mode);
})).then((modes: IMode[]) => {
let promises: Promise[] = [];
modes.forEach((mode) => {
let promise = fn(mode);
if (promise) {
promises.push(promise);
}
});
return Promise.join(promises);
}).then((value) => {
this.telemetryService.publicLog(LanguageServiceTaskSystem.TelemetryEventName, telemetryEvent);
return value;
}, (err) => {
telemetryEvent.success = false;
this.telemetryService.publicLog(LanguageServiceTaskSystem.TelemetryEventName, telemetryEvent);
return Promise.wrapError(err);
})
};
}
}
......@@ -98,9 +98,9 @@ export interface TaskDescription {
args?: string[];
/**
* Whether the task is running in watching mode or not.
* Whether the task is a background task or not.
*/
isWatching?: boolean;
isBackground?: boolean;
/**
* Whether the task should prompt on close for confirmation if running.
......@@ -201,7 +201,7 @@ export interface ITaskExecuteResult {
};
active?: {
same: boolean;
watching: boolean;
background: boolean;
};
}
......@@ -242,5 +242,5 @@ export interface TaskConfiguration {
/**
* The build system to use. If omitted program is used.
*/
buildSystem?: string;
_runner?: string;
}
\ No newline at end of file
......@@ -59,13 +59,15 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { IOutputService, IOutputChannelRegistry, Extensions as OutputExt, IOutputChannel } from 'vs/workbench/parts/output/common/output';
import { ITerminalService } from 'vs/workbench/parts/terminal/common/terminal';
import { ITaskSystem, ITaskSummary, ITaskExecuteResult, TaskExecuteKind, TaskError, TaskErrors, TaskConfiguration, TaskDescription, TaskSystemEvents } from 'vs/workbench/parts/tasks/common/taskSystem';
import { ITaskService, TaskServiceEvents } from 'vs/workbench/parts/tasks/common/taskService';
import { templates as taskTemplates } from 'vs/workbench/parts/tasks/common/taskTemplates';
import { LanguageServiceTaskSystem, LanguageServiceTaskConfiguration } from 'vs/workbench/parts/tasks/common/languageServiceTaskSystem';
import * as FileConfig from 'vs/workbench/parts/tasks/node/processRunnerConfiguration';
import { ProcessRunnerSystem } from 'vs/workbench/parts/tasks/node/processRunnerSystem';
import { TerminalTaskSystem } from './terminalTaskSystem';
import { ProcessRunnerDetector } from 'vs/workbench/parts/tasks/node/processRunnerDetector';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
......@@ -631,7 +633,9 @@ class TaskService extends EventEmitter implements ITaskService {
@IModelService modelService: IModelService, @IExtensionService extensionService: IExtensionService,
@IQuickOpenService quickOpenService: IQuickOpenService,
@IEnvironmentService private environmentService: IEnvironmentService,
@IConfigurationResolverService private configurationResolverService: IConfigurationResolverService) {
@IConfigurationResolverService private configurationResolverService: IConfigurationResolverService,
@ITerminalService private terminalService: ITerminalService
) {
super();
this.modeService = modeService;
......@@ -740,10 +744,15 @@ class TaskService extends EventEmitter implements ITaskService {
throw new TaskError(Severity.Info, nls.localize('TaskSystem.noConfiguration', 'No task runner configured.'), TaskErrors.NotConfigured);
}
let result: ITaskSystem = null;
if (config.buildSystem === 'service') {
result = new LanguageServiceTaskSystem(<LanguageServiceTaskConfiguration>config, this.telemetryService, this.modeService);
} else if (this.isRunnerConfig(config)) {
if (this.isRunnerConfig(config)) {
result = new ProcessRunnerSystem(<FileConfig.ExternalTaskRunnerConfiguration>config, this.markerService, this.modelService, this.telemetryService, this.outputService, this.configurationResolverService, TaskService.OutputChannelId, clearOutput);
} else if (this.isTerminalConfig(config)) {
result = new TerminalTaskSystem(
<FileConfig.ExternalTaskRunnerConfiguration>config,
this.terminalService, this.outputService, this.markerService,
this.modelService, this.configurationResolverService, this.telemetryService,
TaskService.OutputChannelId
);
}
if (result === null) {
this._taskSystemPromise = null;
......@@ -776,7 +785,11 @@ class TaskService extends EventEmitter implements ITaskService {
}
private isRunnerConfig(config: TaskConfiguration): boolean {
return !config.buildSystem || config.buildSystem === 'program';
return !config._runner || config._runner === 'program';
}
private isTerminalConfig(config: TaskConfiguration): boolean {
return config._runner === 'terminal';
}
private hasDetectorSupport(config: FileConfig.ExternalTaskRunnerConfiguration): boolean {
......@@ -826,7 +839,7 @@ class TaskService extends EventEmitter implements ITaskService {
let executeResult = fn(taskSystem);
if (executeResult.kind === TaskExecuteKind.Active) {
let active = executeResult.active;
if (active.same && active.watching) {
if (active.same && active.background) {
this.messageService.show(Severity.Info, nls.localize('TaskSystem.activeSame', 'The task is already active and in watch mode. To terminate the task use `F1 > terminate task`'));
} else {
throw new TaskError(Severity.Warning, nls.localize('TaskSystem.active', 'There is an active running task right now. Terminate it first before executing another task.'), TaskErrors.RunningTask);
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import path = require('path');
import * as nls from 'vs/nls';
import * as Objects from 'vs/base/common/objects';
import { CharCode } from 'vs/base/common/charCode';
import * as Platform from 'vs/base/common/platform';
import * as Async from 'vs/base/common/async';
import { TPromise } from 'vs/base/common/winjs.base';
import { IStringDictionary } from 'vs/base/common/collections';
import Severity from 'vs/base/common/severity';
import { EventEmitter } from 'vs/base/common/eventEmitter';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { TerminateResponse } from 'vs/base/common/processes';
import { IMarkerService } from 'vs/platform/markers/common/markers';
import { ValidationStatus } from 'vs/base/common/parsers';
import { IModelService } from 'vs/editor/common/services/modelService';
import { ProblemMatcher } from 'vs/platform/markers/common/problemMatcher';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
import { ITerminalService, ITerminalInstance } from 'vs/workbench/parts/terminal/common/terminal';
import { TerminalConfigHelper } from 'vs/workbench/parts/terminal/electron-browser/terminalConfigHelper';
import { IOutputService, IOutputChannel } from 'vs/workbench/parts/output/common/output';
import { StartStopProblemCollector, WatchingProblemCollector, ProblemCollectorEvents } from 'vs/workbench/parts/tasks/common/problemCollectors';
import { ITaskSystem, ITaskSummary, ITaskExecuteResult, TaskExecuteKind, TaskError, TaskErrors, TaskRunnerConfiguration, TaskDescription, ShowOutput, TelemetryEvent, Triggers, TaskSystemEvents, TaskEvent, TaskType } from 'vs/workbench/parts/tasks/common/taskSystem';
import * as FileConfig from '../node/processRunnerConfiguration';
interface TerminalData {
terminal: ITerminalInstance;
promise: TPromise<ITaskSummary>;
}
class TerminalDecoder {
// See https://en.wikipedia.org/wiki/ANSI_escape_code & http://stackoverflow.com/questions/25189651/how-to-remove-ansi-control-chars-vt100-from-a-java-string &
// https://www.npmjs.com/package/strip-ansi
private static ANSI_CONTROL_SEQUENCE: RegExp = /\x1b[[()#;?]*(?:\d{1,4}(?:;\d{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
private remaining: string;
public write(data: string): string[] {
let result: string[] = [];
let value = this.remaining
? this.remaining + data.replace(TerminalDecoder.ANSI_CONTROL_SEQUENCE, '')
: data.replace(TerminalDecoder.ANSI_CONTROL_SEQUENCE, '');
if (value.length < 1) {
return result;
}
let start = 0;
let ch: number;
while (start < value.length && ((ch = value.charCodeAt(start)) === CharCode.CarriageReturn || ch === CharCode.LineFeed)) {
start++;
}
let idx = start;
while (idx < value.length) {
ch = value.charCodeAt(idx);
if (ch === CharCode.CarriageReturn || ch === CharCode.LineFeed) {
result.push(value.substring(start, idx));
idx++;
while (idx < value.length && ((ch = value.charCodeAt(idx)) === CharCode.CarriageReturn || ch === CharCode.LineFeed)) {
idx++;
}
start = idx;
} else {
idx++;
}
}
this.remaining = start < value.length ? value.substr(start) : null;
return result;
}
public end(): string {
return this.remaining;
}
}
export class TerminalTaskSystem extends EventEmitter implements ITaskSystem {
public static TelemetryEventName: string = 'taskService';
private validationStatus: ValidationStatus;
private buildTaskIdentifier: string;
private testTaskIdentifier: string;
private configuration: TaskRunnerConfiguration;
private outputChannel: IOutputChannel;
private activeTasks: IStringDictionary<TerminalData>;
constructor(private fileConfig: FileConfig.ExternalTaskRunnerConfiguration, private terminalService: ITerminalService, private outputService: IOutputService,
private markerService: IMarkerService, private modelService: IModelService, private configurationResolverService: IConfigurationResolverService,
private telemetryService: ITelemetryService, outputChannelId: string) {
super();
this.outputChannel = this.outputService.getChannel(outputChannelId);
this.clearOutput();
this.activeTasks = Object.create(null);
let parseResult = FileConfig.parse(fileConfig, this);
this.validationStatus = parseResult.validationStatus;
this.configuration = parseResult.configuration;
this.buildTaskIdentifier = parseResult.defaultBuildTaskIdentifier;
this.testTaskIdentifier = parseResult.defaultTestTaskIdentifier;
if (!this.validationStatus.isOK()) {
this.showOutput();
}
}
public log(value: string): void {
this.outputChannel.append(value + '\n');
}
private showOutput(): void {
this.outputChannel.show(true);
}
private clearOutput(): void {
this.outputChannel.clear();
}
public build(): ITaskExecuteResult {
if (!this.buildTaskIdentifier) {
throw new TaskError(Severity.Info, nls.localize('TerminalTaskSystem.noBuildTask', 'No build task defined in tasks.json'), TaskErrors.NoBuildTask);
}
return this.run(this.buildTaskIdentifier, Triggers.shortcut);
}
public rebuild(): ITaskExecuteResult {
return null;
}
public clean(): ITaskExecuteResult {
return null;
}
public runTest(): ITaskExecuteResult {
return null;
}
public run(taskIdentifier: string, trigger: string = Triggers.command): ITaskExecuteResult {
let task = this.configuration.tasks[taskIdentifier];
if (!task) {
throw new TaskError(Severity.Info, nls.localize('TerminalTaskSystem.noTask', 'Task \'{0}\' not found', taskIdentifier), TaskErrors.TaskNotFound);
}
let telemetryEvent: TelemetryEvent = {
trigger: trigger,
command: 'other',
success: true
};
try {
let result = this.executeTask(task, telemetryEvent);
result.promise = result.promise.then((summary) => {
this.telemetryService.publicLog(TerminalTaskSystem.TelemetryEventName, telemetryEvent);
return summary;
}, (error) => {
telemetryEvent.success = false;
this.telemetryService.publicLog(TerminalTaskSystem.TelemetryEventName, telemetryEvent);
return TPromise.wrapError<ITaskSummary>(error);
});
return result;
} catch (error) {
telemetryEvent.success = false;
this.telemetryService.publicLog(TerminalTaskSystem.TelemetryEventName, telemetryEvent);
if (error instanceof TaskError) {
throw error;
} else if (error instanceof Error) {
this.log(error.message);
throw new TaskError(Severity.Error, error.message, TaskErrors.UnknownError);
} else {
this.log(error.toString());
throw new TaskError(Severity.Error, nls.localize('TerminalTaskSystem.unknownError', 'A unknown error has occurred while executing a task. See task output log for details.'), TaskErrors.UnknownError);
}
}
}
public isActive(): TPromise<boolean> {
return TPromise.as(false);
}
public isActiveSync(): boolean {
return false;
}
public canAutoTerminate(): boolean {
return false;
}
public terminate(): TPromise<TerminateResponse> {
return null;
}
public tasks(): TPromise<TaskDescription[]> {
let result: TaskDescription[];
if (!this.configuration || !this.configuration.tasks) {
result = [];
} else {
result = Object.keys(this.configuration.tasks).map(key => this.configuration.tasks[key]);
}
return TPromise.as(result);
}
private executeTask(task: TaskDescription, telemetryEvent: TelemetryEvent): ITaskExecuteResult {
let terminalData = this.activeTasks[task.id];
if (terminalData && terminalData.promise) {
if (task.showOutput === ShowOutput.Always) {
terminalData.terminal.setVisible(true);
}
return { kind: TaskExecuteKind.Active, active: { same: true, background: task.isBackground }, promise: terminalData.promise };
} else {
let terminal: ITerminalInstance = undefined;
let promise: TPromise<ITaskSummary> = undefined;
if (task.isBackground) {
promise = new TPromise<ITaskSummary>((resolve, reject) => {
let watchingProblemMatcher = new WatchingProblemCollector(this.resolveMatchers(task.problemMatchers), this.markerService, this.modelService);
let toUnbind: IDisposable[] = [];
let event: TaskEvent = { taskId: task.id, taskName: task.name, type: TaskType.Watching };
let eventCounter: number = 0;
toUnbind.push(watchingProblemMatcher.addListener2(ProblemCollectorEvents.WatchingBeginDetected, () => {
eventCounter++;
this.emit(TaskSystemEvents.Active, event);
}));
toUnbind.push(watchingProblemMatcher.addListener2(ProblemCollectorEvents.WatchingEndDetected, () => {
eventCounter--;
this.emit(TaskSystemEvents.Inactive, event);
}));
watchingProblemMatcher.aboutToStart();
let delayer: Async.Delayer<any> = null;
let decoder = new TerminalDecoder();
terminal = this.createTerminal(task);
terminal.onData((data: string) => {
decoder.write(data).forEach(line => {
watchingProblemMatcher.processLine(line);
if (delayer === null) {
delayer = new Async.Delayer(3000);
}
delayer.trigger(() => {
watchingProblemMatcher.forceDelivery();
delayer = null;
});
});
});
terminal.onExit((exitCode) => {
watchingProblemMatcher.dispose();
toUnbind = dispose(toUnbind);
toUnbind = null;
for (let i = 0; i < eventCounter; i++) {
this.emit(TaskSystemEvents.Inactive, event);
}
eventCounter = 0;
if (exitCode && exitCode === 1 && watchingProblemMatcher.numberOfMatches === 0 && task.showOutput !== ShowOutput.Never) {
this.terminalService.setActiveInstance(terminal);
this.terminalService.showPanel(false);
}
resolve({ exitCode });
});
});
} else {
promise = new TPromise<ITaskSummary>((resolve, reject) => {
terminal = this.createTerminal(task);
this.emit(TaskSystemEvents.Active, event);
let decoder = new TerminalDecoder();
let startStopProblemMatcher = new StartStopProblemCollector(this.resolveMatchers(task.problemMatchers), this.markerService, this.modelService);
terminal.onData((data: string) => {
decoder.write(data).forEach((line) => {
startStopProblemMatcher.processLine(line);
});
});
terminal.onExit((exitCode) => {
startStopProblemMatcher.processLine(decoder.end());
startStopProblemMatcher.done();
startStopProblemMatcher.dispose();
this.emit(TaskSystemEvents.Inactive, event);
delete this.activeTasks[task.id];
resolve({ exitCode });
});
this.terminalService.setActiveInstance(terminal);
if (task.showOutput === ShowOutput.Always) {
this.terminalService.showPanel(false);
}
});
}
this.terminalService.setActiveInstance(terminal);
if (task.showOutput === ShowOutput.Always) {
this.terminalService.showPanel(false);
}
this.activeTasks[task.id] = { terminal, promise };
return { kind: TaskExecuteKind.Started, started: {}, promise: promise };
}
}
private createTerminal(task: TaskDescription): ITerminalInstance {
let { command, args } = this.resolveCommandAndArgs(task);
let terminalName = nls.localize('TerminalTaskSystem.terminalName', 'Task - {0}', task.name);
if (this.configuration.isShellCommand) {
let shellConfig = (this.terminalService.configHelper as TerminalConfigHelper).getShell();
let shellArgs = shellConfig.args.slice(0);
let toAdd: string[] = [];
let commandLine: string;
if (Platform.isWindows) {
toAdd.push('/d', '/c');
let quotedCommand: boolean = false;
let quotedArg: boolean = false;
let quoted = this.ensureDoubleQuotes(command);
let commandPieces: string[] = [];
commandPieces.push(quoted.value);
quotedCommand = quoted.quoted;
if (args) {
args.forEach((arg) => {
quoted = this.ensureDoubleQuotes(arg);
commandPieces.push(quoted.value);
quotedArg = quotedArg && quoted.quoted;
});
}
if (quotedCommand) {
if (quotedArg) {
commandLine = '"' + commandPieces.join(' ') + '"';
} else {
if (commandPieces.length > 1) {
commandLine = '"' + commandPieces[0] + '"' + ' ' + commandPieces.slice(1).join(' ');
} else {
commandLine = '"' + commandPieces[0] + '"';
}
}
} else {
commandLine = commandPieces.join(' ');
}
} else {
toAdd.push('-c');
commandLine = `${command} ${args.join(' ')}`;
}
toAdd.forEach(element => {
if (!shellArgs.some(arg => arg.toLowerCase() === element)) {
shellArgs.push(element);
}
});
shellArgs.push(commandLine);
return this.terminalService.createInstance(terminalName, shellConfig.executable, shellArgs, true);
} else {
return this.terminalService.createInstance(terminalName, command, args, true);
}
}
private resolveCommandAndArgs(task: TaskDescription): { command: string, args: string[] } {
let args: string[] = this.configuration.args ? this.configuration.args.slice() : [];
// We need to first pass the task name
if (!task.suppressTaskName) {
if (this.fileConfig.taskSelector) {
args.push(this.fileConfig.taskSelector + task.name);
} else {
args.push(task.name);
}
}
// And then additional arguments
if (task.args) {
args = args.concat(task.args);
}
args = this.resolveVariables(args);
let command: string = this.resolveVariable(this.configuration.command);
return { command, args };
}
private resolveVariables(value: string[]): string[] {
return value.map(s => this.resolveVariable(s));
}
private resolveMatchers<T extends ProblemMatcher>(values: T[]): T[] {
if (values.length === 0) {
return values;
}
let result: T[] = [];
values.forEach((matcher) => {
if (!matcher.filePrefix) {
result.push(matcher);
} else {
let copy = Objects.clone(matcher);
copy.filePrefix = this.resolveVariable(copy.filePrefix);
result.push(copy);
}
});
return result;
}
private resolveVariable(value: string): string {
return this.configurationResolverService.resolve(value);
}
private static doubleQuotes = /^[^"].* .*[^"]$/;
private ensureDoubleQuotes(value: string) {
if (TerminalTaskSystem.doubleQuotes.test(value)) {
return {
value: '"' + value + '"',
quoted: true
};
} else {
return {
value: value,
quoted: value.length > 0 && value[0] === '"' && value[value.length - 1] === '"'
};
}
}
private static WellKnowCommands: IStringDictionary<boolean> = {
'ant': true,
'cmake': true,
'eslint': true,
'gradle': true,
'grunt': true,
'gulp': true,
'jake': true,
'jenkins': true,
'jshint': true,
'make': true,
'maven': true,
'msbuild': true,
'msc': true,
'nmake': true,
'npm': true,
'rake': true,
'tsc': true,
'xbuild': true
};
public getSanitizedCommand(cmd: string): string {
let result = cmd.toLowerCase();
let index = result.lastIndexOf(path.sep);
if (index !== -1) {
result = result.substring(index + 1);
}
if (TerminalTaskSystem.WellKnowCommands[result]) {
return result;
}
return 'other';
}
}
\ No newline at end of file
......@@ -451,7 +451,7 @@ class ConfigurationParser {
name: globals.command,
showOutput: globals.showOutput,
suppressTaskName: true,
isWatching: isWatching,
isBackground: isWatching,
promptOnClose: promptOnClose,
echoCommand: globals.echoCommand,
};
......@@ -539,15 +539,15 @@ class ConfigurationParser {
if (Types.isStringArray(externalTask.args)) {
task.args = externalTask.args.slice();
}
task.isWatching = false;
task.isBackground = false;
if (!Types.isUndefined(externalTask.isWatching)) {
task.isWatching = !!externalTask.isWatching;
task.isBackground = !!externalTask.isWatching;
}
task.promptOnClose = true;
if (!Types.isUndefined(externalTask.promptOnClose)) {
task.promptOnClose = !!externalTask.promptOnClose;
} else {
task.promptOnClose = !task.isWatching;
task.promptOnClose = !task.isBackground;
}
if (Types.isString(externalTask.showOutput)) {
task.showOutput = TaskSystem.ShowOutput.fromString(externalTask.showOutput);
......
......@@ -90,7 +90,7 @@ export class ProcessRunnerSystem extends EventEmitter implements ITaskSystem {
public build(): ITaskExecuteResult {
if (this.activeTaskIdentifier) {
let task = this.configuration.tasks[this.activeTaskIdentifier];
return { kind: TaskExecuteKind.Active, active: { same: this.activeTaskIdentifier === this.defaultBuildTaskIdentifier, watching: task.isWatching }, promise: this.activeTaskPromise };
return { kind: TaskExecuteKind.Active, active: { same: this.activeTaskIdentifier === this.defaultBuildTaskIdentifier, background: task.isBackground }, promise: this.activeTaskPromise };
}
if (!this.defaultBuildTaskIdentifier) {
throw new TaskError(Severity.Info, nls.localize('TaskRunnerSystem.noBuildTask', 'No task is marked as a build task in the tasks.json. Mark a task with \'isBuildCommand\'.'), TaskErrors.NoBuildTask);
......@@ -109,7 +109,7 @@ export class ProcessRunnerSystem extends EventEmitter implements ITaskSystem {
public runTest(): ITaskExecuteResult {
if (this.activeTaskIdentifier) {
let task = this.configuration.tasks[this.activeTaskIdentifier];
return { kind: TaskExecuteKind.Active, active: { same: this.activeTaskIdentifier === this.defaultTestTaskIdentifier, watching: task.isWatching }, promise: this.activeTaskPromise };
return { kind: TaskExecuteKind.Active, active: { same: this.activeTaskIdentifier === this.defaultTestTaskIdentifier, background: task.isBackground }, promise: this.activeTaskPromise };
}
if (!this.defaultTestTaskIdentifier) {
throw new TaskError(Severity.Info, nls.localize('TaskRunnerSystem.noTestTask', 'No test task configured.'), TaskErrors.NoTestTask);
......@@ -120,7 +120,7 @@ export class ProcessRunnerSystem extends EventEmitter implements ITaskSystem {
public run(taskIdentifier: string): ITaskExecuteResult {
if (this.activeTaskIdentifier) {
let task = this.configuration.tasks[this.activeTaskIdentifier];
return { kind: TaskExecuteKind.Active, active: { same: this.activeTaskIdentifier === taskIdentifier, watching: task.isWatching }, promise: this.activeTaskPromise };
return { kind: TaskExecuteKind.Active, active: { same: this.activeTaskIdentifier === taskIdentifier, background: task.isBackground }, promise: this.activeTaskPromise };
}
return this.executeTask(taskIdentifier);
}
......@@ -239,7 +239,7 @@ export class ProcessRunnerSystem extends EventEmitter implements ITaskSystem {
let prompt: string = Platform.isWindows ? '>' : '$';
this.log(`running command${prompt} ${command} ${args.join(' ')}`);
}
if (task.isWatching) {
if (task.isBackground) {
let watchingProblemMatcher = new WatchingProblemCollector(this.resolveMatchers(task.problemMatchers), this.markerService, this.modelService);
let toUnbind: IDisposable[] = [];
let event: TaskEvent = { taskId: task.id, taskName: task.name, type: TaskType.Watching };
......
......@@ -73,7 +73,7 @@ class TaskBuilder {
showOutput: TaskSystem.ShowOutput.Always,
suppressTaskName: false,
echoCommand: false,
isWatching: false,
isBackground: false,
promptOnClose: true,
problemMatchers: []
};
......@@ -99,8 +99,8 @@ class TaskBuilder {
return this;
}
public isWatching(value: boolean): TaskBuilder {
this.result.isWatching = value;
public isBackground(value: boolean): TaskBuilder {
this.result.isBackground = value;
return this;
}
......@@ -307,7 +307,7 @@ suite('Tasks Configuration parsing tests', () => {
let builder = new ConfiguationBuilder('tsc');
builder.task('tsc').
suppressTaskName(true).
isWatching(true).
isBackground(true).
promptOnClose(false);
testGobalCommand(
{
......@@ -627,7 +627,7 @@ suite('Tasks Configuration parsing tests', () => {
showOutput(TaskSystem.ShowOutput.Never).
echoCommand(true).
args(['--p']).
isWatching(true).
isBackground(true).
promptOnClose(false);
let result = testConfiguration(external, builder);
......@@ -833,7 +833,7 @@ suite('Tasks Configuration parsing tests', () => {
]
};
let builder = new ConfiguationBuilder('tsc');
builder.task('taskName').isWatching(true).promptOnClose(false);
builder.task('taskName').isBackground(true).promptOnClose(false);
testConfiguration(external, builder);
});
......@@ -943,7 +943,7 @@ suite('Tasks Configuration parsing tests', () => {
assert.strictEqual(actual.showOutput, expected.showOutput, 'showOutput');
assert.strictEqual(actual.suppressTaskName, expected.suppressTaskName, 'suppressTaskName');
assert.strictEqual(actual.echoCommand, expected.echoCommand, 'echoCommand');
assert.strictEqual(actual.isWatching, expected.isWatching, 'isWatching');
assert.strictEqual(actual.isBackground, expected.isBackground, 'isBackground');
assert.strictEqual(actual.promptOnClose, expected.promptOnClose, 'promptOnClose');
assert.strictEqual(typeof actual.problemMatchers, typeof expected.problemMatchers);
if (actual.problemMatchers && expected.problemMatchers) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册