diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 77d26a05b04..c53f11f1500 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -40,7 +40,7 @@ "command": ".\\scripts\\test.bat" }, "group": "test", - "terminal": { + "presentation": { "echo": true, "reveal": "always" } diff --git a/extensions/grunt/package.json b/extensions/grunt/package.json index 94ea88bbc30..d8aabcc4133 100644 --- a/extensions/grunt/package.json +++ b/extensions/grunt/package.json @@ -44,7 +44,7 @@ }, "taskTypes": [ { - "taskType": "grunt", + "type": "grunt", "required": ["task"], "properties": { "task": { diff --git a/extensions/grunt/src/main.ts b/extensions/grunt/src/main.ts index a3a933e0043..2a228fbf9d8 100644 --- a/extensions/grunt/src/main.ts +++ b/extensions/grunt/src/main.ts @@ -34,12 +34,15 @@ export function activate(_context: vscode.ExtensionContext): void { taskProvider.dispose(); taskProvider = undefined; } else if (!taskProvider && autoDetect === 'on') { - taskProvider = vscode.workspace.registerTaskProvider({ + taskProvider = vscode.workspace.registerTaskProvider('grunt', { provideTasks: () => { if (!detectorPromise) { detectorPromise = getGruntTasks(); } return detectorPromise; + }, + resolveTask(_task: vscode.Task): vscode.Task | undefined { + return undefined; } }); } @@ -81,7 +84,7 @@ function getOutputChannel(): vscode.OutputChannel { return _channel; } -interface GruntTaskIdentifier extends vscode.TaskIdentifier { +interface GruntTaskKind extends vscode.TaskKind { task: string; file?: string; } @@ -150,13 +153,13 @@ async function getGruntTasks(): Promise { let matches = regExp.exec(line); if (matches && matches.length === 2) { let taskName = matches[1]; - let identifier: GruntTaskIdentifier = { + let kind: GruntTaskKind = { type: 'grunt', task: taskName }; let task = taskName.indexOf(' ') === -1 - ? new vscode.ShellTask(identifier, taskName, `${command} ${taskName}`) - : new vscode.ShellTask(identifier, taskName, `${command} "${taskName}"`); + ? new vscode.Task(kind, taskName, new vscode.ShellExecution(`${command} ${taskName}`)) + : new vscode.Task(kind, taskName, new vscode.ShellExecution(`${command} "${taskName}"`)); result.push(task); let lowerCaseTaskName = taskName.toLowerCase(); if (lowerCaseTaskName === 'build') { diff --git a/extensions/gulp/package.json b/extensions/gulp/package.json index 6a9845ce00a..c999dec8645 100644 --- a/extensions/gulp/package.json +++ b/extensions/gulp/package.json @@ -41,6 +41,22 @@ "description": "%config.gulp.autoDetect%" } } - } + }, + "taskTypes": [ + { + "type": "gulp", + "required": ["task"], + "properties": { + "task": { + "type": "string", + "description": "The Gulp task to customize" + }, + "file": { + "type": "string", + "description": "The Gulp file that provides the task. Can be omitted." + } + } + } + ] } } \ No newline at end of file diff --git a/extensions/gulp/src/main.ts b/extensions/gulp/src/main.ts index 49b13ca1d85..8113f61e4b9 100644 --- a/extensions/gulp/src/main.ts +++ b/extensions/gulp/src/main.ts @@ -34,12 +34,15 @@ export function activate(_context: vscode.ExtensionContext): void { taskProvider.dispose(); taskProvider = undefined; } else if (!taskProvider && autoDetect === 'on') { - taskProvider = vscode.workspace.registerTaskProvider({ + taskProvider = vscode.workspace.registerTaskProvider('gulp', { provideTasks: () => { if (!gulpPromise) { gulpPromise = getGulpTasks(); } return gulpPromise; + }, + resolveTask(_task: vscode.Task): vscode.Task | undefined { + return undefined; } }); } @@ -81,7 +84,7 @@ function getOutputChannel(): vscode.OutputChannel { return _channel; } -interface GulpTaskIdentifier extends vscode.TaskIdentifier { +interface GulpTaskKind extends vscode.TaskKind { task: string; file?: string; } @@ -126,11 +129,11 @@ async function getGulpTasks(): Promise { if (line.length === 0) { continue; } - let identifier: GulpTaskIdentifier = { + let kind: GulpTaskKind = { type: 'gulp', task: line }; - let task = new vscode.ShellTask(identifier, line, `${gulpCommand} ${line}`); + let task = new vscode.Task(kind, line, new vscode.ShellExecution(`${gulpCommand} ${line}`)); result.push(task); let lowerCaseLine = line.toLowerCase(); if (lowerCaseLine === 'build') { diff --git a/extensions/jake/package.json b/extensions/jake/package.json index cb3eca33145..3745ed144c0 100644 --- a/extensions/jake/package.json +++ b/extensions/jake/package.json @@ -44,7 +44,7 @@ }, "taskTypes": [ { - "taskType": "jake", + "type": "jake", "required": ["task"], "properties": { "task": { diff --git a/extensions/jake/src/main.ts b/extensions/jake/src/main.ts index 1e9ef387aba..17964886f16 100644 --- a/extensions/jake/src/main.ts +++ b/extensions/jake/src/main.ts @@ -34,12 +34,15 @@ export function activate(_context: vscode.ExtensionContext): void { taskProvider.dispose(); taskProvider = undefined; } else if (!taskProvider && autoDetect === 'on') { - taskProvider = vscode.workspace.registerTaskProvider({ + taskProvider = vscode.workspace.registerTaskProvider('jake', { provideTasks: () => { if (!jakePromise) { jakePromise = getJakeTasks(); } return jakePromise; + }, + resolveTask(_task: vscode.Task): vscode.Task | undefined { + return undefined; } }); } @@ -81,7 +84,7 @@ function getOutputChannel(): vscode.OutputChannel { return _channel; } -interface JakeTaskIdentifier extends vscode.TaskIdentifier { +interface JakeTaskKind extends vscode.TaskKind { task: string; file?: string; } @@ -130,11 +133,11 @@ async function getJakeTasks(): Promise { let matches = regExp.exec(line); if (matches && matches.length === 2) { let taskName = matches[1]; - let identifier: JakeTaskIdentifier = { + let kind: JakeTaskKind = { type: 'jake', task: taskName }; - let task = new vscode.ShellTask(identifier, taskName, `${jakeCommand} ${taskName}`); + let task = new vscode.Task(kind, taskName, new vscode.ShellExecution(`${jakeCommand} ${taskName}`)); result.push(task); let lowerCaseLine = line.toLowerCase(); if (lowerCaseLine === 'build') { diff --git a/extensions/npm/package.json b/extensions/npm/package.json index 9d626265d36..882e751c9ab 100644 --- a/extensions/npm/package.json +++ b/extensions/npm/package.json @@ -41,6 +41,22 @@ "description": "%config.npm.autoDetect%" } } - } + }, + "taskTypes": [ + { + "type": "npm", + "required": ["script"], + "properties": { + "script": { + "type": "string", + "description": "The npm script to customize" + }, + "file": { + "type": "string", + "description": "The package.json file that provides the task. Can be omitted." + } + } + } + ] } } \ No newline at end of file diff --git a/extensions/npm/src/main.ts b/extensions/npm/src/main.ts index e115aa95986..54d3ae76f0c 100644 --- a/extensions/npm/src/main.ts +++ b/extensions/npm/src/main.ts @@ -23,9 +23,12 @@ export function activate(_context: vscode.ExtensionContext): void { taskProvider.dispose(); taskProvider = undefined; } else if (!taskProvider && autoDetect === 'on') { - taskProvider = vscode.workspace.registerTaskProvider({ + taskProvider = vscode.workspace.registerTaskProvider('npm', { provideTasks: () => { return getNpmScriptsAsTasks(); + }, + resolveTask(_task: vscode.Task): vscode.Task | undefined { + return undefined; } }); } @@ -59,7 +62,7 @@ async function readFile(file: string): Promise { }); } -interface NpmTaskIdentifier extends vscode.TaskIdentifier { +interface NpmTaskKind extends vscode.TaskKind { script: string; file?: string; } @@ -87,11 +90,11 @@ async function getNpmScriptsAsTasks(): Promise { const result: vscode.Task[] = []; Object.keys(json.scripts).forEach(each => { - const identifier: NpmTaskIdentifier = { + const kind: NpmTaskKind = { type: 'npm', script: each }; - const task = new vscode.ShellTask(identifier, `run ${each}`, `npm run ${each}`); + const task = new vscode.Task(kind, `run ${each}`, new vscode.ShellExecution(`npm run ${each}`)); const lowerCaseTaskName = each.toLowerCase(); if (lowerCaseTaskName === 'build') { task.group = vscode.TaskGroup.Build; @@ -101,7 +104,7 @@ async function getNpmScriptsAsTasks(): Promise { result.push(task); }); // add some 'well known' npm tasks - result.push(new vscode.ShellTask({ type: 'npm', script: 'install' } as NpmTaskIdentifier, `install`, `npm install`)); + result.push(new vscode.Task({ type: 'npm', script: 'install' } as NpmTaskKind, `install`, new vscode.ShellExecution(`npm install`))); return Promise.resolve(result); } catch (e) { return Promise.resolve(emptyTasks); diff --git a/extensions/typescript/package.json b/extensions/typescript/package.json index 317bc75cc90..9636fcda22d 100644 --- a/extensions/typescript/package.json +++ b/extensions/typescript/package.json @@ -458,6 +458,18 @@ "url": "http://json.schemastore.org/typings" } ], + "taskTypes": [ + { + "type": "typescript", + "required": ["tsconfig"], + "properties": { + "tsconfig": { + "type": "string", + "description": "The tsconfig file that defines the TS build" + } + } + } + ], "problemPatterns": [ { "name": "tsc", diff --git a/extensions/typescript/src/features/taskProvider.ts b/extensions/typescript/src/features/taskProvider.ts index 0cb9034224a..0fa5afd1900 100644 --- a/extensions/typescript/src/features/taskProvider.ts +++ b/extensions/typescript/src/features/taskProvider.ts @@ -22,8 +22,8 @@ const exists = (file: string): Promise => }); -interface TypeScriptTaskIdentifier extends vscode.TaskIdentifier { - configFile: string; +interface TypeScriptTaskIdentifier extends vscode.TaskKind { + tsconfig: string; } /** @@ -53,14 +53,18 @@ class TscTaskProvider implements vscode.TaskProvider { return projects.map(configFile => { const configFileName = path.relative(rootPath, configFile); - const identifier: TypeScriptTaskIdentifier = { type: 'typescript', configFile: configFileName }; - const buildTask = new vscode.ShellTask(identifier, `build ${configFileName}`, `${command} -p "${configFile}"`, '$tsc'); + const identifier: TypeScriptTaskIdentifier = { type: 'typescript', tsconfig: configFileName }; + const buildTask = new vscode.Task(identifier, `build ${configFileName}`, new vscode.ShellExecution(`${command} -p "${configFile}"`), '$tsc'); buildTask.source = 'tsc'; buildTask.group = vscode.TaskGroup.Build; return buildTask; }); } + public resolveTask(_task: vscode.Task): vscode.Task | undefined { + return undefined; + } + private async getAllTsConfigs(token: vscode.CancellationToken): Promise { const out = new Set(); const configs = (await this.getTsConfigForActiveFile(token)).concat(await this.getTsConfigsInWorkspace()); @@ -158,7 +162,7 @@ export default class TypeScriptTaskProviderManager { this.taskProviderSub.dispose(); this.taskProviderSub = undefined; } else if (!this.taskProviderSub && autoDetect === 'on') { - this.taskProviderSub = vscode.workspace.registerTaskProvider(new TscTaskProvider(this.lazyClient)); + this.taskProviderSub = vscode.workspace.registerTaskProvider('typescript', new TscTaskProvider(this.lazyClient)); } } } \ No newline at end of file diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 666734b3540..2d65428674b 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -86,7 +86,55 @@ declare module 'vscode' { panel?: TaskPanelKind; } - export interface ProcessTaskOptions { + /** + * A grouping for tasks. The editor by default supports the + * 'Clean', 'Build', 'RebuildAll' and 'Test' group. + */ + export class TaskGroup { + + /** + * The clean task group; + */ + public static Clean: TaskGroup; + + /** + * The build task group; + */ + public static Build: TaskGroup; + + /** + * The rebuild all task group; + */ + public static RebuildAll: TaskGroup; + + /** + * The test all task group; + */ + public static Test: TaskGroup; + + private constructor(id: string, label: string); + } + + + /** + * A structure that defines a task kind in the system. + * The value must be JSON-stringifyable. + */ + export interface TaskKind { + /** + * The task type as defined by the extension implementing a + * task provider. Examples are 'grunt', 'npm' or 'tsc'. + * Usually a task provider defines more properties to identify + * a task. They need to be defined in the package.json of the + * extension under the 'taskKinds' extension point. + */ + readonly type: string; + } + + /** + * Options for a process execution + */ + export interface ProcessExecutionOptions { /** * The current working directory of the executed program or shell. * If omitted the tools current workspace root is used. @@ -101,100 +149,28 @@ declare module 'vscode' { env?: { [key: string]: string }; } - export namespace TaskGroup { - /** - * The clean task group - */ - export const Clean: 'clean'; - /** - * The build task group. If a task is part of the build task group - * it can be executed via the run build short cut. - */ - export const Build: 'build'; - /** - * The rebuild all task group - */ - export const RebuildAll: 'rebuildAll'; - /** - * The test task group. If a task is part of the test task group - * it can be executed via the run test short cut. - */ - export const Test: 'test'; - } - /** - * An identifer to uniquely identify a task in the system. - * The value must be JSON-stringifyable. + * The execution of a task happens as a external process + * without shell interaction. */ - export interface TaskIdentifier { - /** - * The task type as defined by the extension implementing a - * task provider. Examples are 'grunt', 'npm' or 'tsc'. - * Usually a task provider defines more properties to identify - * a task. They need to be defined in the package.json of the - * extension under the 'taskTypes' extension point. - */ - readonly type: string; - } - - /** - * A task that starts an external process. - */ - export class ProcessTask { + export class ProcessExecution { /** - * Creates a process task. + * Creates a process execution. * - * @param identifier: the task's identifier as defined in the 'taskTypes' extension point. - * @param name the task's name. Is presented in the user interface. - * @param process the process to start. - * @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. + * @param process The process to start. + * @param options Optional options for the started process. */ - constructor(identifier: TaskIdentifier, name: string, process: string, problemMatchers?: string | string[]); + constructor(process: string, options?: ProcessExecutionOptions); /** - * Creates a process task. + * Creates a process execution. * - * @param identifier: the task's identifier as defined in the 'taskTypes' extension point. - * @param name the task's name. Is presented in the user interface. - * @param process the process to start. - * @param args arguments to be passed to the process. - * @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. + * @param process The process to start. + * @param args Arguments to be passed to the process. + * @param options Optional options for the started process. */ - constructor(identifier: TaskIdentifier, name: string, process: string, args: string[], problemMatchers?: string | string[]); - - /** - * Creates a process task. - * - * @param identifier: the task's identifier as defined in the 'taskTypes' extension point. - * @param name the task's name. Is presented in the user interface. - * @param process the process to start. - * @param args arguments to be passed to the process. - * @param options additional options for the started process. - * @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(identifier: TaskIdentifier, name: string, process: string, args: string[], options: ProcessTaskOptions, problemMatchers?: string | string[]); - - /** - * The task's identifier. - */ - identifier: TaskIdentifier; - - /** - * The task's name - */ - name: string; - - /** - * Whether the task is a background task or not. - */ - isBackground: boolean; + constructor(process: string, args: string[], options?: ProcessExecutionOptions); /** * The process to be executed. @@ -206,43 +182,21 @@ declare module 'vscode' { */ args: string[]; - /** - * A human-readable string describing the source of this - * shell task, e.g. 'gulp' or 'npm'. - */ - source: string | undefined; - - /** - * The task group this tasks belongs to. See TaskGroup - * for a predefined set of available groups. - * Defaults to undefined meaning that the task doesn't - * belong to any special group. - */ - group: string | undefined; - /** * The process options used when the process is executed. - * Defaults to an empty object literal. + * Defaults to undefined. */ - options: ProcessTaskOptions; - - /** - * The presentation options. Defaults to an empty literal. - */ - presentationOptions: TaskPresentationOptions; - - /** - * The problem matchers attached to the task. Defaults to an empty - * array. - */ - problemMatchers: string[]; + options?: ProcessExecutionOptions; } - export type ShellTaskOptions = { + /** + * Options for a shell execution + */ + export type ShellExecutionOptions = { /** * The shell executable. */ - executable: string; + executable?: string; /** * The arguments to be passed to the shell executable used to run the task. @@ -261,89 +215,90 @@ declare module 'vscode' { * the parent process' environment. */ env?: { [key: string]: string }; - } | { - /** - * The current working directory of the executed shell. - * If omitted the tools current workspace root is used. - */ - cwd: string; + }; - /** - * The additional environment of the executed shell. If omitted - * the parent process' environment is used. If provided it is merged with - * the parent process' environment. - */ - env?: { [key: string]: string }; - } | { - /** - * The current working directory of the executed shell. - * If omitted the tools current workspace root is used. - */ - cwd?: string; - /** - * The additional environment of the executed shell. If omitted - * the parent process' environment is used. If provided it is merged with - * the parent process' environment. - */ - env: { [key: string]: string }; - }; + export class ShellExecution { + /** + * Creates a process execution. + * + * @param commandLine The command line to execute. + * @param options Optional options for the started the shell. + */ + constructor(commandLine: string, options?: ShellExecutionOptions); + + /** + * The shell command line + */ + commandLine: string; + + /** + * The shell options used when the command line is executed in a shell. + * Defaults to undefined. + */ + options?: ShellExecutionOptions; + } /** - * A task that executes a shell command. + * A task to execute */ - export class ShellTask { + export class Task { /** - * Creates a shell task. + * Creates a new task. A task without an exection set is resolved + * before executed. * - * @param identifier: the task's identifier as defined in the 'taskTypes' extension point. - * @param name the task's name. Is presented in the user interface. - * @param commandLine the command line to execute. + * @param kind The task kind as defined in the 'taskKinds' extension point. + * @param name The task's name. Is presented in the user interface. + */ + constructor(kind: TaskKind, name: string); + + /** + * Creates a new task. + * + * @param kind The task kind as defined in the 'taskKinds' extension point. + * @param name The task's name. Is presented in the user interface. + * @param execution The process or shell execution. + */ + constructor(kind: TaskKind, name: string, execution: ProcessExecution | ShellExecution); + + /** + * Creates a new task. + * + * @param kind The task kind as defined in the 'taskKinds' extension point. + * @param name The task's name. 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(identifier: TaskIdentifier, name: string, commandLine: string, problemMatchers?: string | string[]); + constructor(kind: TaskKind, name: string, execution: ProcessExecution | ShellExecution, problemMatchers?: string | string[]); /** - * Creates a shell task. - * - * @param identifier: the task's identifier as defined in the 'taskTypes' extension point. - * @param name the task's name. Is presented in the user interface. - * @param commandLine the command line to execute. - * @param options additional options used when creating the shell. - * @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. + * The task's kind. */ - constructor(identifier: TaskIdentifier, name: string, commandLine: string, options: ShellTaskOptions, problemMatchers?: string | string[]); - - /** - * The task's identifier. - */ - identifier: TaskIdentifier; + kind: TaskKind; /** * The task's name */ name: string; + /** + * The task's execution engine + */ + execution: ProcessExecution | ShellExecution; + /** * Whether the task is a background task or not. */ isBackground: boolean; - /** - * The command line to execute. - */ - commandLine: string; - /** * A human-readable string describing the source of this * shell task, e.g. 'gulp' or 'npm'. */ - source: string | undefined; + source?: string; /** * The task group this tasks belongs to. See TaskGroup @@ -351,13 +306,7 @@ declare module 'vscode' { * Defaults to undefined meaning that the task doesn't * belong to any special group. */ - group: string | undefined; - - /** - * The shell options used when the shell is executed. Defaults to an - * empty object literal. - */ - options: ShellTaskOptions; + group?: TaskGroup; /** * The presentation options. Defaults to an empty literal. @@ -371,29 +320,36 @@ declare module 'vscode' { problemMatchers: string[]; } - export type Task = ProcessTask | ShellTask; - /** * A task provider allows to add tasks to the task service. * A task provider is registerd via #workspace.registerTaskProvider. */ export interface TaskProvider { /** - * Provides additional tasks. + * Provides tasks. * @param token A cancellation token. - * @return a #TaskSet + * @return an array of tasks */ provideTasks(token: CancellationToken): ProviderResult; + + /** + * Resolves a task the has no execution set. + * @param task The task to resolve. + * @param token A cancellation token. + * @return the resolved task + */ + resolveTask(task: Task, token: CancellationToken): ProviderResult; } export namespace workspace { /** * Register a task provider. * + * @param type The task kind type this provider is registered for. * @param provider A task provider. * @return A [disposable](#Disposable) that unregisters this provider when being disposed. */ - export function registerTaskProvider(provider: TaskProvider): Disposable; + export function registerTaskProvider(type: string, provider: TaskProvider): Disposable; } export namespace window { diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index c32ae55014a..6fa4d07407c 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -429,7 +429,7 @@ export function createApiFactory( getConfiguration: (section?: string): vscode.WorkspaceConfiguration => { return extHostConfiguration.getConfiguration(section); }, - registerTaskProvider: proposedApiFunction(extension, (provider: vscode.TaskProvider) => { + registerTaskProvider: proposedApiFunction(extension, (type: string, provider: vscode.TaskProvider) => { return extHostTask.registerTaskProvider(extension, provider); }) }; @@ -518,8 +518,9 @@ export function createApiFactory( TaskRevealKind: extHostTypes.TaskRevealKind, TaskPanelKind: extHostTypes.TaskPanelKind, TaskGroup: extHostTypes.TaskGroup, - ShellTask: extHostTypes.ShellTask, - ProcessTask: extHostTypes.ProcessTask + ProcessExecution: extHostTypes.ProcessExecution, + ShellExecution: extHostTypes.ShellExecution, + Task: extHostTypes.Task }; }; } diff --git a/src/vs/workbench/api/node/extHostTask.ts b/src/vs/workbench/api/node/extHostTask.ts index bfbcfb16fa9..17f57d3b284 100644 --- a/src/vs/workbench/api/node/extHostTask.ts +++ b/src/vs/workbench/api/node/extHostTask.ts @@ -256,7 +256,7 @@ namespace CommandOptions { function isShellConfiguration(value: any): value is { executable: string; shellArgs?: string[] } { return value && typeof value.executable === 'string'; } - export function from(value: vscode.ShellTaskOptions | vscode.ProcessTaskOptions): TaskSystem.CommandOptions { + export function from(value: vscode.ShellExecutionOptions | vscode.ProcessExecutionOptions): TaskSystem.CommandOptions { if (value === void 0 || value === null) { return undefined; } @@ -321,37 +321,41 @@ namespace Tasks { return undefined; } let command: TaskSystem.CommandConfiguration; - if (task instanceof types.ProcessTask) { - command = getProcessCommand(task); - } else if (task instanceof types.ShellTask) { - command = getShellCommand(task); + let execution = task.execution; + if (execution instanceof types.ProcessExecution) { + command = getProcessCommand(execution); + } else if (execution instanceof types.ShellExecution) { + command = getShellCommand(execution); } else { return undefined; } if (command === void 0) { return undefined; } + command.presentation = PresentationOptions.from(task.presentationOptions); let source = { kind: TaskSystem.TaskSourceKind.Extension, label: typeof task.source === 'string' ? task.source : extension.name, detail: extension.id }; let label = nls.localize('task.label', '{0}: {1}', source.label, task.name); - let id = `${extension.id}.${task.identifierKey}`; - let identifier: TaskSystem.TaskIdentifier = { - _key: task.identifierKey, - type: task.identifier.type + let key = (task as types.Task).kindKey; + let kind = (task as types.Task).kind; + let id = `${extension.id}.${key}`; + let taskKind: TaskSystem.TaskIdentifier = { + _key: key, + type: kind.type }; - Objects.assign(identifier, task.identifier); + Objects.assign(taskKind, kind); let result: TaskSystem.ContributedTask = { _id: id, // uuidMap.getUUID(identifier), _source: source, _label: label, - type: task.identifier.type, - defines: identifier, + type: kind.type, + defines: taskKind, name: task.name, identifier: label, - group: types.TaskGroup.is(task.group) ? task.group : undefined, + group: task.group ? (task.group as types.TaskGroup).id : undefined, command: command, isBackground: !!task.isBackground, problemMatchers: task.problemMatchers.slice() @@ -359,7 +363,7 @@ namespace Tasks { return result; } - function getProcessCommand(value: vscode.ProcessTask): TaskSystem.CommandConfiguration { + function getProcessCommand(value: vscode.ProcessExecution): TaskSystem.CommandConfiguration { if (typeof value.process !== 'string') { return undefined; } @@ -368,7 +372,7 @@ namespace Tasks { args: Strings.from(value.args), runtime: TaskSystem.RuntimeType.Process, suppressTaskName: true, - presentation: PresentationOptions.from(value.presentationOptions) + presentation: undefined }; if (value.options) { result.options = CommandOptions.from(value.options); @@ -376,14 +380,14 @@ namespace Tasks { return result; } - function getShellCommand(value: vscode.ShellTask): TaskSystem.CommandConfiguration { + function getShellCommand(value: vscode.ShellExecution): TaskSystem.CommandConfiguration { if (typeof value.commandLine !== 'string') { return undefined; } let result: TaskSystem.CommandConfiguration = { name: value.commandLine, runtime: TaskSystem.RuntimeType.Shell, - presentation: PresentationOptions.from(value.presentationOptions) + presentation: undefined }; if (value.options) { result.options = CommandOptions.from(value.options); diff --git a/src/vs/workbench/api/node/extHostTypes.ts b/src/vs/workbench/api/node/extHostTypes.ts index b6a8d7604d3..f86ab747725 100644 --- a/src/vs/workbench/api/node/extHostTypes.ts +++ b/src/vs/workbench/api/node/extHostTypes.ts @@ -1015,22 +1015,6 @@ export class DocumentLink { } } -export enum FileLocationKind { - Auto = 1, - - Relative = 2, - - Absolute = 3 -} - -export enum ApplyToKind { - AllDocuments = 1, - - OpenDocuments = 2, - - ClosedDocuments = 3 -} - export enum TaskRevealKind { Always = 1, @@ -1047,44 +1031,170 @@ export enum TaskPanelKind { New = 3 } -export class BaseTask { +export class TaskGroup implements vscode.TaskGroup { + private _id: string; + private _label: string; + + public static Clean: TaskGroup = new TaskGroup('clean', 'Clean'); + + public static Build: TaskGroup = new TaskGroup('build', 'Build'); + + public static RebuildAll: TaskGroup = new TaskGroup('rebuildAll', 'RebuildAll'); + + public static Test: TaskGroup = new TaskGroup('clean', 'Clean'); + + constructor(id: string, label: string) { + if (typeof id !== 'string') { + throw illegalArgument('name'); + } + if (typeof label !== 'string') { + throw illegalArgument('name'); + } + this._id = id; + this._label = label; + } + + get id(): string { + return this._id; + } +} + +export class ProcessExecution implements vscode.ProcessExecution { + + private _process: string; + private _args: string[]; + private _options: vscode.ProcessExecutionOptions; + + constructor(process: string, options?: vscode.ProcessExecutionOptions); + constructor(process: string, args: string[], options?: vscode.ProcessExecutionOptions); + constructor(process: string, varg1?: string[] | vscode.ProcessExecutionOptions, varg2?: vscode.ProcessExecutionOptions) { + if (typeof process !== 'string') { + throw illegalArgument('process'); + } + this._process = process; + if (varg1 !== void 0) { + if (Array.isArray(varg1)) { + this._args = varg1; + this._options = varg2; + } else { + this._options = varg1; + } + } + if (this._args === void 0) { + this._args = []; + } + } + + + get process(): string { + return this._process; + } + + set process(value: string) { + if (typeof value !== 'string') { + throw illegalArgument('process'); + } + this._process = value; + } + + get args(): string[] { + return this._args; + } + + set args(value: string[]) { + if (!Array.isArray(value)) { + value = []; + } + this._args = value; + } + + get options(): vscode.ProcessExecutionOptions { + return this._options; + } + + set options(value: vscode.ProcessExecutionOptions) { + this._options = value; + } +} + +export class ShellExecution implements vscode.ShellExecution { + + private _commandLine: string; + private _options: vscode.ShellExecutionOptions; + + constructor(commandLine: string, options?: vscode.ShellExecutionOptions) { + if (typeof commandLine !== 'string') { + throw illegalArgument('commandLine'); + } + this._commandLine = commandLine; + this._options = options; + } + + get commandLine(): string { + return this._commandLine; + } + + set commandLine(value: string) { + if (typeof value !== 'string') { + throw illegalArgument('commandLine'); + } + this._commandLine = value; + } + + get options(): vscode.ShellExecutionOptions { + return this._options; + } + + set options(value: vscode.ShellExecutionOptions) { + this._options = value; + } +} + +export class Task implements vscode.Task { + + private _kind: vscode.TaskKind; + private _kindKey: string; private _name: string; + private _execution: ProcessExecution | ShellExecution; private _problemMatchers: string[]; - private _identifier: vscode.TaskIdentifier; - private _identifierKey: string; private _isBackground: boolean; private _source: string; - private _group: string; + private _group: TaskGroup; private _presentationOptions: vscode.TaskPresentationOptions; - constructor(identifier: vscode.TaskIdentifier, name: string, problemMatchers: string[]) { - this.identifier = identifier; + + constructor(kind: vscode.TaskKind, name: string); + constructor(kind: vscode.TaskKind, name: string, execution: ProcessExecution | ShellExecution); + constructor(kind: vscode.TaskKind, name: string, execution: ProcessExecution | ShellExecution, problemMatchers?: string | string[]); + + constructor(kind: vscode.TaskKind, name: string, execution?: ProcessExecution | ShellExecution, problemMatchers?: string[]) { + this.kind = kind; this.name = name; + this.execution = execution; this._problemMatchers = problemMatchers || []; this._isBackground = false; - this._presentationOptions = Object.create(null); } - get identifier(): vscode.TaskIdentifier { - return this._identifier; + get kind(): vscode.TaskKind { + return this._kind; } - set identifier(value: vscode.TaskIdentifier) { + set kind(value: vscode.TaskKind) { if (value === void 0 || value === null) { - throw illegalArgument('Identifier can\'t be undefined or null'); + throw illegalArgument('Kind can\'t be undefined or null'); } - this._identifierKey = undefined; - this._identifier = value; + this._kindKey = undefined; + this._kind = value; } - get identifierKey(): string { - if (!this._identifierKey) { + get kindKey(): string { + if (!this._kindKey) { const hash = crypto.createHash('md5'); - hash.update(JSON.stringify(this._identifier)); - this._identifierKey = hash.digest('hex'); + hash.update(JSON.stringify(this._kind)); + this._kindKey = hash.digest('hex'); } - return this._identifierKey; + return this._kindKey; } get name(): string { @@ -1098,6 +1208,28 @@ export class BaseTask { this._name = value; } + get execution(): ProcessExecution | ShellExecution { + return this._execution; + } + + set execution(value: ProcessExecution | ShellExecution) { + if (value === null) { + value = undefined; + } + this._execution = value; + } + + get problemMatchers(): string[] { + return this._problemMatchers; + } + + set problemMatchers(value: string[]) { + if (!Array.isArray(value)) { + value = []; + } + this._problemMatchers = value; + } + get isBackground(): boolean { return this._isBackground; } @@ -1124,18 +1256,15 @@ export class BaseTask { this._source = value; } - get group(): string { + get group(): TaskGroup { return this._group; } - set group(value: string) { + set group(value: TaskGroup) { if (value === void 0 || value === null) { this._group = undefined; return; } - if (typeof value !== 'string' || value.length === 0) { - throw illegalArgument('group must be a string of length > 0'); - } this._group = value; } @@ -1144,176 +1273,13 @@ export class BaseTask { } set presentationOptions(value: vscode.TaskPresentationOptions) { - if (value === void 0 || value === null) { - value = Object.create(null); + if (value === null) { + value = undefined; } this._presentationOptions = value; } - - get problemMatchers(): string[] { - return this._problemMatchers; - } - - set problemMatchers(value: string[]) { - if (!Array.isArray(value)) { - value = []; - } - this._problemMatchers = value; - } } -/* -namespace ProblemMatcher { - export function is(value: any): value is vscode.ProblemMatcher { - let candidate: vscode.ProblemMatcher = value; - return candidate && !!candidate.pattern; - } -} -*/ - -namespace ShellOptions { - export function is(value: any): value is vscode.ShellTaskOptions { - return value && ((typeof value.executable === 'string') || (typeof value.cwd === 'string') || !!value.env); - } -} - -export namespace TaskGroup { - /** - * The clean task group - */ - export const Clean: 'clean' = 'clean'; - - /** - * The build task group - */ - export const Build: 'build' = 'build'; - - /** - * The rebuild all task group - */ - export const RebuildAll: 'rebuildAll' = 'rebuildAll'; - - /** - * The test task group - */ - export const Test: 'test' = 'test'; - - export function is(value: string): value is string { - return value === Clean || value === Build || value === RebuildAll || value === Test; - } -} - -export class ProcessTask extends BaseTask { - - private _process: string; - private _args: string[]; - private _options: vscode.ProcessTaskOptions; - - constructor(identifier: vscode.TaskIdentifier, name: string, process: string, args?: string[], problemMatchers?: string | string[]); - constructor(identifier: vscode.TaskIdentifier, name: string, process: string, args: string[] | undefined, options: vscode.ProcessTaskOptions, problemMatchers?: string | string[]); - constructor(identifier: vscode.TaskIdentifier, name: string, process: string, varg1?: string[], varg2?: vscode.ProcessTaskOptions | string | string[], varg3?: string | string[]) { - if (typeof process !== 'string') { - throw illegalArgument('process'); - } - let args: string[]; - let options: vscode.ProcessTaskOptions; - let problemMatchers: string | string[]; - - args = varg1 || []; - if (varg2) { - if (Array.isArray(varg2) || typeof varg2 === 'string') { - problemMatchers = varg2; - } else { - options = varg2; - } - } - if (varg3 && !problemMatchers) { - problemMatchers = varg3; - } - let pm: string[]; - if (problemMatchers && (typeof problemMatchers === 'string')) { - pm = [problemMatchers]; - } else if (Array.isArray(problemMatchers)) { - pm = problemMatchers; - } - pm = pm || []; - super(identifier, name, pm); - this._process = process; - this._args = args; - this._options = options || Object.create(null); - } - - get process(): string { - return this._process; - } - - get args(): string[] { - return this._args; - } - - set args(value: string[]) { - if (!Array.isArray(value)) { - value = []; - } - this._args = value; - } - - get options(): vscode.ProcessTaskOptions { - return this._options; - } - - set options(value: vscode.ProcessTaskOptions) { - if (value === void 0 || value === null) { - value = Object.create(null); - } - this._options = value; - } -} - -export class ShellTask extends BaseTask implements vscode.ShellTask { - - private _commandLine: string; - private _options: vscode.ShellTaskOptions; - - constructor(identifier: vscode.TaskIdentifier, name: string, commandLine: string, problemMatchers?: string | string[]); - constructor(identifier: vscode.TaskIdentifier, name: string, commandLine: string, options: vscode.ShellTaskOptions, problemMatchers?: string | string[]); - constructor(identifier: vscode.TaskIdentifier, name: string, commandLine: string, optionsOrProblemMatchers?: vscode.ShellTaskOptions | string | string[], problemMatchers?: string | string[]) { - if (typeof commandLine !== 'string') { - throw illegalArgument('commandLine'); - } - let options: vscode.ShellTaskOptions = undefined; - let pm: string[]; - if (ShellOptions.is(optionsOrProblemMatchers)) { - options = optionsOrProblemMatchers; - } else { - problemMatchers = optionsOrProblemMatchers; - } - if (problemMatchers && (typeof problemMatchers === 'string')) { - pm = [problemMatchers]; - } else if (Array.isArray(problemMatchers)) { - pm = problemMatchers; - } - pm = pm || []; - super(identifier, name, pm); - this._commandLine = commandLine; - this._options = options || Object.create(null); - } - - get commandLine(): string { - return this._commandLine; - } - - get options(): vscode.ShellTaskOptions { - return this._options; - } - - set options(value: vscode.ShellTaskOptions) { - if (value === void 0 || value === null) { - value = Object.create(null); - } - this._options = value; - } -} export enum ProgressLocation { SourceControl = 1, diff --git a/src/vs/workbench/parts/tasks/common/backlog.txt b/src/vs/workbench/parts/tasks/common/backlog.txt new file mode 100644 index 00000000000..44e22c25081 --- /dev/null +++ b/src/vs/workbench/parts/tasks/common/backlog.txt @@ -0,0 +1,6 @@ +Allow configuring of problem matchers for auto detected build tasks +Run Build > list of build tasks > user selected task with PM > show UI to select problem matcher > open tasks.json +Task Menu only in insider +Telemetry for task + +Polish task menu. \ No newline at end of file diff --git a/src/vs/workbench/parts/tasks/common/taskTypeRegistry.ts b/src/vs/workbench/parts/tasks/common/taskTypeRegistry.ts index dcd613f4062..41f888b7f4a 100644 --- a/src/vs/workbench/parts/tasks/common/taskTypeRegistry.ts +++ b/src/vs/workbench/parts/tasks/common/taskTypeRegistry.ts @@ -20,7 +20,7 @@ const taskTypeSchema: IJSONSchema = { type: 'object', additionalProperties: false, properties: { - taskType: { + type: { type: 'string', description: nls.localize('TaskType.description', 'The actual task type') }, @@ -36,7 +36,7 @@ const taskTypeSchema: IJSONSchema = { namespace Configuration { export interface TaskTypeDescription { - taskType?: string; + type?: string; required?: string[]; properties?: IJSONSchemaMap; } @@ -45,7 +45,7 @@ namespace Configuration { if (!value) { return undefined; } - let taskType = Types.isString(value.taskType) ? value.taskType : undefined; + let taskType = Types.isString(value.type) ? value.type : undefined; if (!taskType || taskType.length === 0) { messageCollector.error(nls.localize('TaskTypeConfiguration.noType', 'The task type configuration is missing the required \'taskType\' property')); return undefined; @@ -64,7 +64,7 @@ namespace Configuration { const taskTypesExtPoint = ExtensionsRegistry.registerExtensionPoint('taskTypes', [], { - description: nls.localize('TaskTypeExtPoint', 'Contributes task types'), + description: nls.localize('TaskTypeExtPoint', 'Contributes task kinds'), type: 'array', items: taskTypeSchema });