提交 9d1f4279 编写于 作者: D Dirk Baeumer

Fixes #1194

上级 12981a3e
......@@ -73,6 +73,10 @@ export class LanguageServiceTaskSystem extends EventEmitter implements ITaskSyst
return false;
}
public canAutoTerminate(): boolean {
return false;
}
public terminate(): TPromise<TerminateResponse> {
return TPromise.as({ success: true });
}
......
......@@ -91,6 +91,11 @@ export interface TaskDescription {
*/
isWatching?: boolean;
/**
* Whether the task should prompt on close for confirmation if running.
*/
promptOnClose?: boolean;
/**
* Controls whether the output of the running tasks is shown or not. Default
* value is "always".
......@@ -197,6 +202,7 @@ export interface ITaskSystem extends IEventEmitter {
run(taskIdentifier: string): ITaskRunResult;
isActive(): TPromise<boolean>;
isActiveSync(): boolean;
canAutoTerminate(): boolean;
terminate(): TPromise<TerminateResponse>;
tasks(): TPromise<TaskDescription[]>;
}
......
......@@ -55,7 +55,12 @@ export namespace Config {
/**
* Whether the executed command is kept alive and is watching the file system.
*/
isWatching?:boolean;
isWatching?: boolean;
/**
* Whether the task should prompt on close for confirmation if running.
*/
promptOnClose?: boolean;
/**
* Controls whether the output view of the running tasks is brought to front or not.
......@@ -133,6 +138,11 @@ export interface Task {
*/
isWatching: boolean;
/**
* Whether the task should prompt on close for confirmation if running.
*/
promptOnClose?: boolean;
/**
* Controls whether the output view of the running tasks is brought to front or not.
* See BaseTaskRunnerConfiguration#showOutput for details.
......@@ -205,6 +215,12 @@ export class TaskParser extends Parser {
if (this.is(json.isWatching, Types.isBoolean)) {
isWatching = json.isWatching;
}
let promptOnClose: boolean = true;
if (this.is(json.promptOnClose, Types.isBoolean)) {
promptOnClose = json.promptOnClose;
} else {
promptOnClose = !isWatching;
}
if (this.is(json.showOutput, Types.isString)) {
showOutput = ShowOutput.fromString(json.showOutput) || ShowOutput.Always;
}
......@@ -229,7 +245,7 @@ export class TaskParser extends Parser {
problemMatcher.push(matcher);
}
}
return { id, name, trigger, executable, isWatching, showOutput, echoCommand, settings, problemMatcher };
return { id, name, trigger, executable, isWatching, promptOnClose, showOutput, echoCommand, settings, problemMatcher };
}
private parseProblemMatcher(json: string | ProblemMatcherConfig.ProblemMatcher): ProblemMatcher {
......
......@@ -699,7 +699,7 @@ class TaskService extends EventEmitter implements ITaskService {
public beforeShutdown(): boolean | TPromise<boolean> {
if (this._taskSystem && this._taskSystem.isActiveSync()) {
if (this.messageService.confirm({
if (this._taskSystem.canAutoTerminate() || this.messageService.confirm({
message: nls.localize('TaskSystem.runningTask', 'There is a task running. Do you want to terminate it?'),
primaryButton: nls.localize('TaskSystem.terminateTask', "Terminate Task")
})) {
......@@ -1060,6 +1060,11 @@ if (Env.enableTasks) {
'description': nls.localize('JsonSchema.watching', 'Whether the executed task is kept alive and is watching the file system.'),
'default': true
},
'promptOnClose': {
'type': 'boolean',
'description': nls.localize('JsonSchema.promptOnClose', 'Whether the user is prompted when VS Code closes with a running background task.'),
'default': false
},
'echoCommand': {
'type': 'boolean',
'description': nls.localize('JsonSchema.echoCommand', 'Controls whether the executed command is echoed to the output. Default is false.'),
......
......@@ -57,6 +57,11 @@ export interface TaskDescription {
*/
isWatching?:boolean;
/**
* Whether the task should prompt on close for confirmation if running.
*/
promptOnClose?: boolean;
/**
* Whether this task maps to the default build command.
*/
......@@ -163,6 +168,11 @@ export interface BaseTaskRunnerConfiguration extends TaskSystem.TaskConfiguratio
*/
isWatching?: boolean;
/**
* Whether the task should prompt on close for confirmation if running.
*/
promptOnClose?: boolean;
/**
* The configuration of the available tasks. A tasks.json file can either
* contain a global problemMatcher property or a tasks property but not both.
......@@ -432,12 +442,19 @@ class ConfigurationParser {
if (!Types.isUndefined(fileConfig.isWatching)) {
isWatching = !!fileConfig.isWatching;
}
let promptOnClose: boolean = true;
if (!Types.isUndefined(fileConfig.promptOnClose)) {
promptOnClose = !!fileConfig.promptOnClose;
} else {
promptOnClose = !isWatching;
}
let task: TaskSystem.TaskDescription = {
id: UUID.generateUuid(),
name: globals.command,
showOutput: globals.showOutput,
suppressTaskName: true,
isWatching: isWatching,
promptOnClose: promptOnClose,
echoCommand: globals.echoCommand,
};
if (hasGlobalMatcher) {
......@@ -528,6 +545,12 @@ class ConfigurationParser {
if (!Types.isUndefined(externalTask.isWatching)) {
task.isWatching = !!externalTask.isWatching;
}
task.promptOnClose = true;
if (!Types.isUndefined(externalTask.promptOnClose)) {
task.promptOnClose = !!externalTask.promptOnClose;
} else {
task.promptOnClose = !task.isWatching;
}
if (Types.isString(externalTask.showOutput)) {
task.showOutput = TaskSystem.ShowOutput.fromString(externalTask.showOutput);
}
......
......@@ -115,6 +115,19 @@ export class ProcessRunnerSystem extends EventEmitter implements ITaskSystem {
return !!this.childProcess;
}
public canAutoTerminate(): boolean {
if (this.childProcess) {
if (this.activeTaskIdentifier) {
let task = this.configuration.tasks[this.activeTaskIdentifier];
if (task) {
return !task.promptOnClose;
}
}
return false;
}
return true;
}
public terminate(): TPromise<TerminateResponse> {
if (this.childProcess) {
return this.childProcess.terminate();
......@@ -270,20 +283,21 @@ export class ProcessRunnerSystem extends EventEmitter implements ITaskSystem {
let event: TaskEvent = { taskId: task.id, taskName: task.name, type: TaskType.SingleRun };
this.emit(TaskSystemEvents.Active, event );
let startStopProblemMatcher = new StartStopProblemCollector(this.resolveMatchers(task.problemMatchers), this.markerService, this.modelService);
this.activeTaskIdentifier = task.id;
let promise = this.childProcess.start().then((success): ITaskSummary => {
this.emit(TaskSystemEvents.Inactive, event);
startStopProblemMatcher.done();
this.childProcessEnded();
startStopProblemMatcher.done();
startStopProblemMatcher.dispose();
this.checkTerminated(task, success);
this.emit(TaskSystemEvents.Inactive, event);
if (success.cmdCode && success.cmdCode === 1 && startStopProblemMatcher.numberOfMatches === 0 && task.showOutput !== ShowOutput.Never) {
this.showOutput();
}
return taskSummary;
}, (error: ErrorData) => {
this.emit(TaskSystemEvents.Inactive, event);
this.childProcessEnded();
startStopProblemMatcher.dispose();
this.emit(TaskSystemEvents.Inactive, event);
return this.handleError(task, error);
}, (progress) => {
let line = Strings.removeAnsiEscapeCodes(progress.line);
......
......@@ -73,6 +73,7 @@ class TaskBuilder {
suppressTaskName: false,
echoCommand: false,
isWatching: false,
promptOnClose: true,
problemMatchers: []
};
}
......@@ -102,6 +103,11 @@ class TaskBuilder {
return this;
}
public promptOnClose(value: boolean): TaskBuilder {
this.result.promptOnClose = value;
return this;
}
public problemMatcher(): ProblemMatcherBuilder {
let builder = new ProblemMatcherBuilder(this);
this.result.problemMatchers.push(builder.result);
......@@ -270,6 +276,51 @@ suite('Tasks Configuration parsing tests', () => {
);
});
test('tasks: global promptOnClose default', () => {
let builder = new ConfiguationBuilder('tsc');
builder.task('tsc').
suppressTaskName(true);
testGobalCommand(
{
version: '0.1.0',
command: "tsc",
promptOnClose: true
},
builder
);
});
test('tasks: global promptOnClose', () => {
let builder = new ConfiguationBuilder('tsc');
builder.task('tsc').
suppressTaskName(true).
promptOnClose(false);
testGobalCommand(
{
version: '0.1.0',
command: "tsc",
promptOnClose: false
},
builder
);
})
test('tasks: global promptOnClose default watching', () => {
let builder = new ConfiguationBuilder('tsc');
builder.task('tsc').
suppressTaskName(true).
isWatching(true).
promptOnClose(false);
testGobalCommand(
{
version: '0.1.0',
command: "tsc",
isWatching: true
},
builder
);
})
test('tasks: global show output never', () => {
let builder = new ConfiguationBuilder('tsc');
builder.
......@@ -578,7 +629,8 @@ suite('Tasks Configuration parsing tests', () => {
showOutput(TaskSystem.ShowOutput.Never).
echoCommand(true).
args(['--p']).
isWatching(true);
isWatching(true).
promptOnClose(false);
let result = testConfiguration(external, builder);
assert.ok(result.defaultTestTaskIdentifier);
......@@ -756,6 +808,53 @@ suite('Tasks Configuration parsing tests', () => {
testConfiguration(external, builder);
});
test('tasks: prompt on close default', () => {
let external: ExternalTaskRunnerConfiguration = {
version: '0.1.0',
command: 'tsc',
tasks: [
{
taskName: 'taskName'
}
]
};
let builder = new ConfiguationBuilder('tsc');
builder.task('taskName').promptOnClose(true);
testConfiguration(external, builder);
});
test('tasks: prompt on close watching', () => {
let external: ExternalTaskRunnerConfiguration = {
version: '0.1.0',
command: 'tsc',
tasks: [
{
taskName: 'taskName',
isWatching: true
}
]
};
let builder = new ConfiguationBuilder('tsc');
builder.task('taskName').isWatching(true).promptOnClose(false);
testConfiguration(external, builder);
});
test('tasks: prompt on close set', () => {
let external: ExternalTaskRunnerConfiguration = {
version: '0.1.0',
command: 'tsc',
tasks: [
{
taskName: 'taskName',
promptOnClose: false
}
]
};
let builder = new ConfiguationBuilder('tsc');
builder.task('taskName').promptOnClose(false);
testConfiguration(external, builder);
});
test('tasks: two tasks', () => {
let external: ExternalTaskRunnerConfiguration = {
version: '0.1.0',
......@@ -847,6 +946,7 @@ suite('Tasks Configuration parsing tests', () => {
assert.strictEqual(actual.suppressTaskName, expected.suppressTaskName, 'suppressTaskName');
assert.strictEqual(actual.echoCommand, expected.echoCommand, 'echoCommand');
assert.strictEqual(actual.isWatching, expected.isWatching, 'isWatching');
assert.strictEqual(actual.promptOnClose, expected.promptOnClose, 'promptOnClose');
assert.strictEqual(typeof actual.problemMatchers, typeof expected.problemMatchers);
if (actual.problemMatchers && expected.problemMatchers) {
assert.strictEqual(actual.problemMatchers.length, expected.problemMatchers.length);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册