From d198a282a3d1f8b056eccb7d98e5fefcfad29239 Mon Sep 17 00:00:00 2001 From: Alvaro Sanchez-Leon Date: Mon, 1 Feb 2021 12:47:55 -0500 Subject: [PATCH] Support plugin tasks using 'TaskScope.Workspace' * Aligns the TaskScope enum definition with vscode see issue [1] and corresponding schemas for Theia [2] and vscode [3] * Supports processing of task configurations provided by plugins with the scope set to TaskScope.Workspace. * Ignores processing of task configurations provided by plugins with the scope set to TaskScope.Global i.e. User tasks. Fixes: #7931 [1] https://github.com/eclipse-theia/theia/issues/7931 [2] https://github.com/eclipse-theia/theia/blob/2aa2fa1ab091ec36ef851c4e364b322301cddb40/packages/plugin/src/theia.d.ts#L8637 [3] https://github.com/microsoft/vscode/blob/50f907f0ba9b0c799a7c1d2f28a625bf30041636/src/vs/vscode.d.ts#L5923 Signed-off-by: Alvaro Sanchez-Leon --- packages/plugin/src/theia.d.ts | 2 +- .../src/browser/provided-task-configurations.ts | 13 +++++++++---- packages/task/src/browser/quick-open-task.ts | 2 +- packages/task/src/browser/task-configurations.ts | 8 ++------ .../task/src/browser/task-definition-registry.ts | 9 +++++++-- packages/task/src/common/task-protocol.ts | 8 ++++++-- 6 files changed, 26 insertions(+), 16 deletions(-) diff --git a/packages/plugin/src/theia.d.ts b/packages/plugin/src/theia.d.ts index 9eb7eb420d397..0ec76a6578a0a 100644 --- a/packages/plugin/src/theia.d.ts +++ b/packages/plugin/src/theia.d.ts @@ -9722,7 +9722,7 @@ declare module '@theia/plugin' { } export enum TaskScope { - /** The task is a global task */ + /** The task is a global task. Global tasks are currently not supported. */ Global = 1, /** The task is a workspace task */ diff --git a/packages/task/src/browser/provided-task-configurations.ts b/packages/task/src/browser/provided-task-configurations.ts index ad625a4287140..c35f2541efec5 100644 --- a/packages/task/src/browser/provided-task-configurations.ts +++ b/packages/task/src/browser/provided-task-configurations.ts @@ -17,7 +17,7 @@ import { inject, injectable } from 'inversify'; import { TaskProviderRegistry } from './task-contribution'; import { TaskDefinitionRegistry } from './task-definition-registry'; -import { TaskConfiguration, TaskCustomization, TaskOutputPresentation, TaskConfigurationScope } from '../common'; +import { TaskConfiguration, TaskCustomization, TaskOutputPresentation, TaskConfigurationScope, TaskScope } from '../common'; @injectable() export class ProvidedTaskConfigurations { @@ -61,6 +61,8 @@ export class ProvidedTaskConfigurations { const providers = await this.taskProviderRegistry.getProviders(); const providedTasks: TaskConfiguration[] = (await Promise.all(providers.map(p => p.provideTasks()))) .reduce((acc, taskArray) => acc.concat(taskArray), []) + // Global/User tasks from providers are not supported. + .filter(task => task.scope !== TaskScope.Global) .map(providedTask => { const originalPresentation = providedTask.presentation || {}; return { @@ -116,12 +118,15 @@ export class ProvidedTaskConfigurations { } } + // Tasks with scope set to 'Workspace' can be customized in a workspace root, and will not match + // providers scope 'TaskScope.Workspace' unless specifically included as below. + const scopes = [scope, TaskScope.Workspace]; // find the task that matches the `customization`. // The scenario where more than one match is found should not happen unless users manually enter multiple customizations for one type of task // If this does happen, return the first match - const matchedTask = matchedTasks.filter(t => - scope === t._scope && definition.properties.all.every(p => t[p] === customization[p]) - )[0]; + const matchedTask = matchedTasks.find(t => + scopes.some(scp => scp === t._scope) && definition.properties.all.every(p => t[p] === customization[p]) + ); return matchedTask; } diff --git a/packages/task/src/browser/quick-open-task.ts b/packages/task/src/browser/quick-open-task.ts index 69cc242c3ed37..c296c67052749 100644 --- a/packages/task/src/browser/quick-open-task.ts +++ b/packages/task/src/browser/quick-open-task.ts @@ -246,7 +246,7 @@ export class QuickOpenTask implements QuickOpenModel, QuickOpenHandler { if (this.workspaceService.opened) { const roots = await this.workspaceService.roots; scopes.push(...roots.map(rootStat => rootStat.resource.toString())); - if (this.workspaceService.saved) { + if (this.workspaceService.saved || groupedTasks.get(TaskScope.Workspace.toString())?.length) { scopes.push(TaskScope.Workspace); } } diff --git a/packages/task/src/browser/task-configurations.ts b/packages/task/src/browser/task-configurations.ts index 925dd8cb7ed41..19d47ee290f31 100644 --- a/packages/task/src/browser/task-configurations.ts +++ b/packages/task/src/browser/task-configurations.ts @@ -302,12 +302,8 @@ export class TaskConfigurations implements Disposable { /** Adds given task to a config file and opens the file to provide ability to edit task configuration. */ async configure(token: number, task: TaskConfiguration): Promise { const scope = task._scope; - if (scope === TaskScope.Global || scope === TaskScope.Workspace) { - return this.taskConfigurationManager.openConfiguration(scope); - } else if (typeof scope !== 'string') { - console.error('Global task cannot be customized'); - // TODO detected tasks of scope workspace or user could be customized in those preferences. - return; + if (scope === TaskScope.Global) { + return this.openUserTasks(); } const workspace = this.workspaceService.workspace; diff --git a/packages/task/src/browser/task-definition-registry.ts b/packages/task/src/browser/task-definition-registry.ts index 26e7beb927a8b..370f3c9939946 100644 --- a/packages/task/src/browser/task-definition-registry.ts +++ b/packages/task/src/browser/task-definition-registry.ts @@ -114,8 +114,13 @@ export class TaskDefinitionRegistry { } const def = this.getDefinition(one); if (def) { - // scope is either a string or an enum value. Anyway...the must exactly match - return def.properties.all.every(p => p === 'type' || one[p] === other[p]) && one._scope === other._scope; + // scope is either a string or an enum value. Anyway...they must exactly match + // "_scope" may hold the Uri to the associated workspace whereas + // "scope" reflects the original TaskConfigurationScope as provided by plugins, + // Matching "_scope" or "scope" are both accepted in order to correlate provided task + // configurations (e.g. TaskScope.Workspace) against already configured tasks. + return def.properties.all.every(p => p === 'type' || one[p] === other[p]) + && (one._scope === other._scope || one.scope === other.scope); } return one.label === other.label && one._source === other._source; } diff --git a/packages/task/src/common/task-protocol.ts b/packages/task/src/common/task-protocol.ts index 682f0668d5c98..871386b6e2377 100644 --- a/packages/task/src/common/task-protocol.ts +++ b/packages/task/src/common/task-protocol.ts @@ -149,10 +149,14 @@ export namespace TaskCustomization { } export enum TaskScope { - Workspace, - Global + Global = 1, + Workspace = 2 } +/** + * The task configuration scopes. + * - `string` represents the associated workspace folder uri. + */ export type TaskConfigurationScope = string | TaskScope.Workspace | TaskScope.Global; export interface TaskConfiguration extends TaskCustomization {