diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index effc4fe6315..18c5dbf463b 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -5074,21 +5074,6 @@ declare module 'vscode' { options?: ShellExecutionOptions; } - /** - * Class used to execute an extension callback as a task. - */ - export class ExtensionCallbackExecution { - /** - * @param callback The callback that will be called when the extension callback task is executed. - */ - constructor(callback: (terminalRenderer: TerminalRenderer, cancellationToken: CancellationToken, thisArg?: any) => Thenable); - - /** - * The callback used to execute the task. - */ - callback: (terminalRenderer: TerminalRenderer, cancellationToken: CancellationToken, thisArg?: any) => Thenable; - } - /** * The scope of a task. */ @@ -5118,7 +5103,6 @@ declare module 'vscode' { * A task to execute */ export class Task { - /** * Creates a new task. * @@ -5131,7 +5115,7 @@ declare module 'vscode' { * or '$eslint'. Problem matchers can be contributed by an extension using * the `problemMatchers` extension point. */ - constructor(taskDefinition: TaskDefinition, scope: WorkspaceFolder | TaskScope.Global | TaskScope.Workspace, name: string, source: string, execution?: ProcessExecution | ShellExecution | ExtensionCallbackExecution, problemMatchers?: string | string[]); + constructor(taskDefinition: TaskDefinition, scope: WorkspaceFolder | TaskScope.Global | TaskScope.Workspace, name: string, source: string, execution?: ProcessExecution | ShellExecution, problemMatchers?: string | string[]); /** * ~~Creates a new task.~~ @@ -5146,7 +5130,7 @@ declare module 'vscode' { * or '$eslint'. Problem matchers can be contributed by an extension using * the `problemMatchers` extension point. */ - constructor(taskDefinition: TaskDefinition, name: string, source: string, execution?: ProcessExecution | ShellExecution | ExtensionCallbackExecution, problemMatchers?: string | string[]); + constructor(taskDefinition: TaskDefinition, name: string, source: string, execution?: ProcessExecution | ShellExecution, problemMatchers?: string | string[]); /** * The task's definition. @@ -5166,7 +5150,7 @@ declare module 'vscode' { /** * The task's execution engine */ - execution?: ProcessExecution | ShellExecution | ExtensionCallbackExecution; + execution?: ProcessExecution | ShellExecution; /** * Whether the task is a background task or not. diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index edbf4b240fa..6db56b3942e 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -1098,4 +1098,43 @@ declare module 'vscode' { readonly activeSignatureHelp?: SignatureHelp; } //#endregion + + /** + * Class used to execute an extension callback as a task. + */ + export class ExtensionCallbackExecution { + /** + * @param callback The callback that will be called when the extension callback task is executed. + */ + constructor(callback: (terminalRenderer: TerminalRenderer, cancellationToken: CancellationToken, thisArg?: any) => Thenable); + + /** + * The callback used to execute the task. + */ + callback: (terminalRenderer: TerminalRenderer, cancellationToken: CancellationToken, thisArg?: any) => Thenable; + } + + /** + * A task to execute + */ + export class TaskWithExtensionCallback extends Task { + /** + * Creates a new task. + * + * @param definition The task definition as defined in the taskDefinitions extension point. + * @param scope Specifies the task's scope. It is either a global or a workspace task or a task for a specific workspace folder. + * @param name The task's name. Is presented in the user interface. + * @param source The task's source (e.g. 'gulp', 'npm', ...). Is presented in the user interface. + * @param execution The process or shell execution. + * @param problemMatchers the names of problem matchers to use, like '$tsc' + * or '$eslint'. Problem matchers can be contributed by an extension using + * the `problemMatchers` extension point. + */ + constructor(taskDefinition: TaskDefinition, scope: WorkspaceFolder | TaskScope.Global | TaskScope.Workspace, name: string, source: string, execution?: ProcessExecution | ShellExecution | ExtensionCallbackExecution, problemMatchers?: string | string[]); + + /** + * The task's execution engine + */ + executionWithExtensionCallback?: ProcessExecution | ShellExecution | ExtensionCallbackExecution; + } } diff --git a/src/vs/workbench/api/electron-browser/mainThreadTask.ts b/src/vs/workbench/api/electron-browser/mainThreadTask.ts index bb5b2f761fb..724cceea194 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadTask.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadTask.ts @@ -32,7 +32,7 @@ import { TaskDefinitionDTO, TaskExecutionDTO, ProcessExecutionOptionsDTO, TaskPresentationOptionsDTO, ProcessExecutionDTO, ShellExecutionDTO, ShellExecutionOptionsDTO, TaskDTO, TaskSourceDTO, TaskHandleDTO, TaskFilterDTO, TaskProcessStartedDTO, TaskProcessEndedDTO, TaskSystemInfoDTO, RunOptionsDTO, - CallbackExecutionDTO + ExtensionCallbackExecutionDTO } from 'vs/workbench/api/shared/tasks'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; @@ -139,7 +139,7 @@ namespace ProcessExecutionOptionsDTO { } namespace ProcessExecutionDTO { - export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CallbackExecutionDTO): value is ProcessExecutionDTO { + export function is(value: ShellExecutionDTO | ProcessExecutionDTO | ExtensionCallbackExecutionDTO): value is ProcessExecutionDTO { let candidate = value as ProcessExecutionDTO; return candidate && !!candidate.process; } @@ -207,7 +207,7 @@ namespace ShellExecutionOptionsDTO { } namespace ShellExecutionDTO { - export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CallbackExecutionDTO): value is ShellExecutionDTO { + export function is(value: ShellExecutionDTO | ProcessExecutionDTO | ExtensionCallbackExecutionDTO): value is ShellExecutionDTO { let candidate = value as ShellExecutionDTO; return candidate && (!!candidate.commandLine || !!candidate.command); } @@ -239,18 +239,18 @@ namespace ShellExecutionDTO { } namespace CallbackExecutionDTO { - export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CallbackExecutionDTO): value is CallbackExecutionDTO { - let candidate = value as CallbackExecutionDTO; + export function is(value: ShellExecutionDTO | ProcessExecutionDTO | ExtensionCallbackExecutionDTO): value is ExtensionCallbackExecutionDTO { + let candidate = value as ExtensionCallbackExecutionDTO; return candidate && candidate.extensionCallback === 'extensionCallback'; } - export function from(value: CommandConfiguration): CallbackExecutionDTO { + export function from(value: CommandConfiguration): ExtensionCallbackExecutionDTO { return { extensionCallback: 'extensionCallback' }; } - export function to(value: CallbackExecutionDTO): CommandConfiguration { + export function to(value: ExtensionCallbackExecutionDTO): CommandConfiguration { return { runtime: RuntimeType.ExtensionCallback, presentation: undefined diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 3eb2fe278a2..7179a57a5ee 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -800,7 +800,7 @@ export function createApiFactory( SymbolInformation: extHostTypes.SymbolInformation, SymbolKind: extHostTypes.SymbolKind, Task: extHostTypes.Task, - Task2: extHostTypes.Task, + TaskWithExtensionCallback: extHostTypes.Task, TaskGroup: extHostTypes.TaskGroup, TaskPanelKind: extHostTypes.TaskPanelKind, TaskRevealKind: extHostTypes.TaskRevealKind, diff --git a/src/vs/workbench/api/node/extHostTask.ts b/src/vs/workbench/api/node/extHostTask.ts index 6597e4ba0c1..def67669a93 100644 --- a/src/vs/workbench/api/node/extHostTask.ts +++ b/src/vs/workbench/api/node/extHostTask.ts @@ -22,7 +22,7 @@ import { TaskDefinitionDTO, TaskExecutionDTO, TaskPresentationOptionsDTO, ProcessExecutionOptionsDTO, ProcessExecutionDTO, ShellExecutionOptionsDTO, ShellExecutionDTO, - CallbackExecutionDTO, + ExtensionCallbackExecutionDTO, TaskDTO, TaskHandleDTO, TaskFilterDTO, TaskProcessStartedDTO, TaskProcessEndedDTO, TaskSystemInfoDTO, TaskSetDTO } from '../shared/tasks'; import { ExtHostVariableResolverService } from 'vs/workbench/api/node/extHostDebugService'; @@ -79,7 +79,7 @@ namespace ProcessExecutionOptionsDTO { } namespace ProcessExecutionDTO { - export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CallbackExecutionDTO): value is ProcessExecutionDTO { + export function is(value: ShellExecutionDTO | ProcessExecutionDTO | ExtensionCallbackExecutionDTO): value is ProcessExecutionDTO { let candidate = value as ProcessExecutionDTO; return candidate && !!candidate.process; } @@ -120,7 +120,7 @@ namespace ShellExecutionOptionsDTO { } namespace ShellExecutionDTO { - export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CallbackExecutionDTO): value is ShellExecutionDTO { + export function is(value: ShellExecutionDTO | ProcessExecutionDTO | ExtensionCallbackExecutionDTO): value is ShellExecutionDTO { let candidate = value as ShellExecutionDTO; return candidate && (!!candidate.commandLine || !!candidate.command); } @@ -153,13 +153,13 @@ namespace ShellExecutionDTO { } } -namespace CallbackExecutionDTO { - export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CallbackExecutionDTO): value is CallbackExecutionDTO { - let candidate = value as CallbackExecutionDTO; +namespace ExtensionCallbackExecutionDTO { + export function is(value: ShellExecutionDTO | ProcessExecutionDTO | ExtensionCallbackExecutionDTO): value is ExtensionCallbackExecutionDTO { + let candidate = value as ExtensionCallbackExecutionDTO; return candidate && candidate.extensionCallback === 'extensionCallback'; } - export function from(value: vscode.ExtensionCallbackExecution): CallbackExecutionDTO { + export function from(value: vscode.ExtensionCallbackExecution): ExtensionCallbackExecutionDTO { return { extensionCallback: 'extensionCallback' }; @@ -199,13 +199,13 @@ namespace TaskDTO { if (value === undefined || value === null) { return undefined; } - let execution: ShellExecutionDTO | ProcessExecutionDTO | CallbackExecutionDTO; + let execution: ShellExecutionDTO | ProcessExecutionDTO | ExtensionCallbackExecutionDTO; if (value.execution instanceof types.ProcessExecution) { execution = ProcessExecutionDTO.from(value.execution); } else if (value.execution instanceof types.ShellExecution) { execution = ShellExecutionDTO.from(value.execution); - } else if (value.execution instanceof types.ExtensionCallbackExecution) { - execution = CallbackExecutionDTO.from(value.execution); + } else if ((value).executionWithExtensionCallback && (value).executionWithExtensionCallback instanceof types.ExtensionCallbackExecution) { + execution = ExtensionCallbackExecutionDTO.from((value).executionWithExtensionCallback); } let definition: TaskDefinitionDTO = TaskDefinitionDTO.from(value.definition); @@ -387,8 +387,13 @@ class ExtensionCallbackExecutionData implements IDisposable { // Regardless of how the task completes, we are done with this extension callback task execution. return this.callbackData.callback(terminalRenderer, this._cancellationSource.token).then( - () => this._onTaskExecutionComplete.fire(this), - () => this._onTaskExecutionComplete.fire(this)); + (success) => { + this._onTaskExecutionComplete.fire(this); + terminalRenderer.terminal.dispose(); + }, (rejected) => { + this._onTaskExecutionComplete.fire(this); + terminalRenderer.terminal.dispose(); + }); } return undefined; @@ -617,11 +622,11 @@ export class ExtHostTask implements ExtHostTaskShape { const taskDTO: TaskDTO = TaskDTO.from(task, handler.extension); taskDTOs.push(taskDTO); - if (CallbackExecutionDTO.is(taskDTO.execution)) { + if (ExtensionCallbackExecutionDTO.is(taskDTO.execution)) { taskIdPromises.push(new Promise((resolve) => { // The ID is calculated on the main thread task side, so, let's call into it here. this._proxy.$createTaskId(taskDTO).then((taskId) => { - this._providedExtensionCallbacks.set(taskId, new ExtensionCallbackExecutionData(task.execution, this._terminalService)); + this._providedExtensionCallbacks.set(taskId, new ExtensionCallbackExecutionData((task).executionWithExtensionCallback, this._terminalService)); resolve(); }); })); diff --git a/src/vs/workbench/api/node/extHostTypes.ts b/src/vs/workbench/api/node/extHostTypes.ts index a255e5945cf..912dac95366 100644 --- a/src/vs/workbench/api/node/extHostTypes.ts +++ b/src/vs/workbench/api/node/extHostTypes.ts @@ -1646,7 +1646,7 @@ export class ExtensionCallbackExecution implements vscode.ExtensionCallbackExecu } } -export class Task implements vscode.Task { +export class Task implements vscode.TaskWithExtensionCallback { private static ExtensionCallbackType: string = 'extensionCallback'; private static ProcessType: string = 'process'; @@ -1733,7 +1733,7 @@ export class Task implements vscode.Task { type: Task.ShellType, id: this._execution.computeId() }; - } else if (this._execution instanceof ExtensionScriptApis) { + } else if (this._execution instanceof ExtensionCallbackExecution) { this._definition = { type: Task.ExtensionCallbackType, id: this._execution.computeId() @@ -1779,18 +1779,34 @@ export class Task implements vscode.Task { this._name = value; } - get execution(): ProcessExecution | ShellExecution | ExtensionCallbackExecution | undefined { + get execution(): ProcessExecution | ShellExecution | undefined { + return (this._execution instanceof ExtensionCallbackExecution) ? undefined : this._execution; + } + + set execution(value: ProcessExecution | ShellExecution | undefined) { + this.executionInternal = value; + } + + get executionWithExtensionCallback(): ProcessExecution | ShellExecution | ExtensionCallbackExecution | undefined { + return this.executionInternal; + } + + set executionWithExtensionCallback(value: ProcessExecution | ShellExecution | ExtensionCallbackExecution | undefined) { + this.executionInternal = value; + } + + private get executionInternal(): ProcessExecution | ShellExecution | ExtensionCallbackExecution | undefined { return this._execution; } - set execution(value: ProcessExecution | ShellExecution | ExtensionCallbackExecution | undefined) { + private set executionInternal(value: ProcessExecution | ShellExecution | ExtensionCallbackExecution | undefined) { if (value === null) { value = undefined; } this.clear(); this._execution = value; let type = this._definition.type; - if (Task.EmptyType === type || Task.ProcessType === type || Task.ShellType === type) { + if (Task.EmptyType === type || Task.ProcessType === type || Task.ShellType === type || Task.ExtensionCallbackType === type) { this.computeDefinitionBasedOnExecution(); } } diff --git a/src/vs/workbench/api/shared/tasks.ts b/src/vs/workbench/api/shared/tasks.ts index ae9b2d3a548..e7a392ac0c3 100644 --- a/src/vs/workbench/api/shared/tasks.ts +++ b/src/vs/workbench/api/shared/tasks.ts @@ -65,7 +65,7 @@ export interface ShellExecutionDTO { options?: ShellExecutionOptionsDTO; } -export interface CallbackExecutionDTO { +export interface ExtensionCallbackExecutionDTO { extensionCallback: 'extensionCallback'; } @@ -83,7 +83,7 @@ export interface TaskHandleDTO { export interface TaskDTO { _id: string; name: string; - execution: ProcessExecutionDTO | ShellExecutionDTO | CallbackExecutionDTO; + execution: ProcessExecutionDTO | ShellExecutionDTO | ExtensionCallbackExecutionDTO; definition: TaskDefinitionDTO; isBackground: boolean; source: TaskSourceDTO; diff --git a/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.ts b/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.ts index a71996a03dc..57d765804d6 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.ts +++ b/src/vs/workbench/parts/tasks/electron-browser/terminalTaskSystem.ts @@ -514,7 +514,9 @@ export class TerminalTaskSystem implements ITaskSystem { let processStartedSignaled = false; terminal.processReady.then(() => { if (!processStartedSignaled) { - this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.ProcessStarted, task, terminal!.processId!)); + if (task.command.runtime !== RuntimeType.ExtensionCallback) { + this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.ProcessStarted, task, terminal!.processId!)); + } processStartedSignaled = true; } }, (_error) => { @@ -581,7 +583,9 @@ export class TerminalTaskSystem implements ITaskSystem { let processStartedSignaled = false; terminal.processReady.then(() => { if (!processStartedSignaled) { - this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.ProcessStarted, task, terminal!.processId!)); + if (task.command.runtime !== RuntimeType.ExtensionCallback) { + this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.ProcessStarted, task, terminal!.processId!)); + } processStartedSignaled = true; } }, (_error) => {