@theia/task 1.37.0-next.8 → 1.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/browser/provided-task-configurations.d.ts +14 -4
- package/lib/browser/provided-task-configurations.d.ts.map +1 -1
- package/lib/browser/provided-task-configurations.js +52 -16
- package/lib/browser/provided-task-configurations.js.map +1 -1
- package/lib/browser/quick-open-task.d.ts +15 -4
- package/lib/browser/quick-open-task.d.ts.map +1 -1
- package/lib/browser/quick-open-task.js +110 -27
- package/lib/browser/quick-open-task.js.map +1 -1
- package/lib/browser/task-contribution.d.ts +13 -4
- package/lib/browser/task-contribution.d.ts.map +1 -1
- package/lib/browser/task-contribution.js +10 -3
- package/lib/browser/task-contribution.js.map +1 -1
- package/lib/browser/task-service.d.ts +5 -2
- package/lib/browser/task-service.d.ts.map +1 -1
- package/lib/browser/task-service.js +6 -3
- package/lib/browser/task-service.js.map +1 -1
- package/package.json +13 -13
- package/src/browser/provided-task-configurations.ts +66 -23
- package/src/browser/quick-open-task.ts +127 -31
- package/src/browser/task-contribution.ts +17 -5
- package/src/browser/task-service.ts +6 -3
- package/LICENSE +0 -642
|
@@ -16,17 +16,19 @@
|
|
|
16
16
|
|
|
17
17
|
import { inject, injectable, optional } from '@theia/core/shared/inversify';
|
|
18
18
|
import { TaskService } from './task-service';
|
|
19
|
-
import { TaskInfo, TaskConfiguration, TaskCustomization, TaskScope, TaskConfigurationScope } from '../common/task-protocol';
|
|
19
|
+
import { TaskInfo, TaskConfiguration, TaskCustomization, TaskScope, TaskConfigurationScope, TaskDefinition } from '../common/task-protocol';
|
|
20
20
|
import { TaskDefinitionRegistry } from './task-definition-registry';
|
|
21
21
|
import URI from '@theia/core/lib/common/uri';
|
|
22
|
-
import { LabelProvider, QuickAccessProvider, QuickAccessRegistry, QuickInputService, PreferenceService } from '@theia/core/lib/browser';
|
|
22
|
+
import { LabelProvider, QuickAccessProvider, QuickAccessRegistry, QuickInputService, QuickPick, PreferenceService } from '@theia/core/lib/browser';
|
|
23
23
|
import { WorkspaceService } from '@theia/workspace/lib/browser';
|
|
24
24
|
import { TerminalService } from '@theia/terminal/lib/browser/base/terminal-service';
|
|
25
25
|
import { TaskNameResolver } from './task-name-resolver';
|
|
26
26
|
import { TaskSourceResolver } from './task-source-resolver';
|
|
27
27
|
import { TaskConfigurationManager } from './task-configuration-manager';
|
|
28
|
-
import { filterItems, QuickInputButton, QuickPickItem, QuickPickItemOrSeparator, QuickPicks } from
|
|
28
|
+
import { filterItems, QuickInputButton, QuickPickItem, QuickPickItemOrSeparator, QuickPicks, QuickPickInput, QuickPickValue } from
|
|
29
|
+
'@theia/core/lib/browser/quick-input/quick-input-service';
|
|
29
30
|
import { CancellationToken } from '@theia/core/lib/common';
|
|
31
|
+
import { nls } from '@theia/core/lib/common/nls';
|
|
30
32
|
import { TriggerAction } from '@theia/monaco-editor-core/esm/vs/platform/quickinput/browser/pickerQuickAccess';
|
|
31
33
|
|
|
32
34
|
export namespace ConfigureTaskAction {
|
|
@@ -34,11 +36,21 @@ export namespace ConfigureTaskAction {
|
|
|
34
36
|
export const TEXT = 'Configure Task';
|
|
35
37
|
}
|
|
36
38
|
|
|
39
|
+
export type TaskEntry = QuickPickItemOrSeparator | QuickPickValue<string>;
|
|
40
|
+
export namespace TaskEntry {
|
|
41
|
+
export function isQuickPickValue(item: QuickPickItemOrSeparator | QuickPickValue<String>): item is QuickPickValue<string> {
|
|
42
|
+
return 'value' in item && typeof item.value === 'string';
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const CHOOSE_TASK = nls.localizeByDefault('Select the task to run');
|
|
47
|
+
export const NO_TASK_TO_RUN = nls.localize('theia/task/noTaskToRun', 'No task to run found. Configure Tasks...');
|
|
48
|
+
|
|
37
49
|
@injectable()
|
|
38
50
|
export class QuickOpenTask implements QuickAccessProvider {
|
|
39
51
|
static readonly PREFIX = 'task ';
|
|
40
52
|
readonly description: string = 'Run Task';
|
|
41
|
-
protected items: Array<
|
|
53
|
+
protected items: Array<TaskEntry> = [];
|
|
42
54
|
|
|
43
55
|
@inject(TaskService)
|
|
44
56
|
protected readonly taskService: TaskService;
|
|
@@ -77,21 +89,61 @@ export class QuickOpenTask implements QuickAccessProvider {
|
|
|
77
89
|
protected async doInit(token: number): Promise<void> {
|
|
78
90
|
const recentTasks = this.taskService.recentTasks;
|
|
79
91
|
const configuredTasks = await this.taskService.getConfiguredTasks(token);
|
|
80
|
-
const
|
|
92
|
+
const providedTypes = this.taskDefinitionRegistry.getAll();
|
|
81
93
|
|
|
82
|
-
const { filteredRecentTasks, filteredConfiguredTasks
|
|
94
|
+
const { filteredRecentTasks, filteredConfiguredTasks } = this.getFilteredTasks(recentTasks, configuredTasks, []);
|
|
83
95
|
const isMulti: boolean = this.workspaceService.isMultiRootWorkspaceOpened;
|
|
84
96
|
this.items = [];
|
|
85
97
|
|
|
86
98
|
const filteredRecentTasksItems = this.getItems(filteredRecentTasks, 'recently used tasks', token, isMulti);
|
|
87
99
|
const filteredConfiguredTasksItems = this.getItems(filteredConfiguredTasks, 'configured tasks', token, isMulti);
|
|
88
|
-
const
|
|
100
|
+
const providedTypeItems = this.createProvidedTypeItems(providedTypes);
|
|
89
101
|
|
|
90
102
|
this.items.push(
|
|
91
103
|
...filteredRecentTasksItems,
|
|
92
104
|
...filteredConfiguredTasksItems,
|
|
93
|
-
...
|
|
105
|
+
...providedTypeItems
|
|
94
106
|
);
|
|
107
|
+
|
|
108
|
+
if (!this.items.length) {
|
|
109
|
+
this.items.push(({
|
|
110
|
+
label: NO_TASK_TO_RUN,
|
|
111
|
+
execute: () => this.configure()
|
|
112
|
+
}));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
protected createProvidedTypeItems(providedTypes: TaskDefinition[]): TaskEntry[] {
|
|
117
|
+
const result: TaskEntry[] = [];
|
|
118
|
+
result.push({ type: 'separator', label: nls.localizeByDefault('contributed') });
|
|
119
|
+
|
|
120
|
+
for (const definition of providedTypes) {
|
|
121
|
+
const type = definition.taskType;
|
|
122
|
+
result.push({
|
|
123
|
+
label: `$(folder) ${type}`,
|
|
124
|
+
value: type,
|
|
125
|
+
/**
|
|
126
|
+
* This function is used in the context of a QuickAccessProvider (triggered from the command palette: '?task').
|
|
127
|
+
* It triggers a call to QuickOpenTask#getPicks,
|
|
128
|
+
* the 'execute' function below is called when the user selects an entry for a task type which triggers the display of
|
|
129
|
+
* the second level quick pick.
|
|
130
|
+
*
|
|
131
|
+
* Due to the asynchronous resolution of second-level tasks, there may be a delay in showing the quick input widget.
|
|
132
|
+
*
|
|
133
|
+
* NOTE: The widget is not delayed in other contexts e.g. by commands (Run Tasks), see the implementation at QuickOpenTask#open
|
|
134
|
+
*
|
|
135
|
+
* To improve the performance, we may consider using a `PickerQuickAccessProvider` instead of a `QuickAccessProvider`,
|
|
136
|
+
* and support providing 'FastAndSlowPicks'.
|
|
137
|
+
*
|
|
138
|
+
* TODO: Consider the introduction and exposure of monaco `PickerQuickAccessProvider` and the corresponding refactoring for this and other
|
|
139
|
+
* users of QuickAccessProvider.
|
|
140
|
+
*/
|
|
141
|
+
execute: () => {
|
|
142
|
+
this.doSecondLevel(type);
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
return result;
|
|
95
147
|
}
|
|
96
148
|
|
|
97
149
|
protected onDidTriggerGearIcon(item: QuickPickItem): void {
|
|
@@ -102,17 +154,54 @@ export class QuickOpenTask implements QuickAccessProvider {
|
|
|
102
154
|
}
|
|
103
155
|
|
|
104
156
|
async open(): Promise<void> {
|
|
157
|
+
this.showMultiLevelQuickPick();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async showMultiLevelQuickPick(): Promise<void> {
|
|
105
161
|
await this.init();
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
162
|
+
const picker: QuickPick<TaskEntry> = this.quickInputService.createQuickPick();
|
|
163
|
+
picker.placeholder = CHOOSE_TASK;
|
|
164
|
+
picker.matchOnDescription = true;
|
|
165
|
+
picker.ignoreFocusOut = false;
|
|
166
|
+
picker.items = this.items;
|
|
167
|
+
|
|
168
|
+
const firstLevelTask = await this.doPickerFirstLevel(picker);
|
|
169
|
+
|
|
170
|
+
if (!!firstLevelTask && TaskEntry.isQuickPickValue(firstLevelTask)) {
|
|
171
|
+
// A taskType was selected
|
|
172
|
+
picker.busy = true;
|
|
173
|
+
await this.doSecondLevel(firstLevelTask.value);
|
|
174
|
+
} else if (!!firstLevelTask && 'execute' in firstLevelTask && typeof firstLevelTask.execute === 'function') {
|
|
175
|
+
firstLevelTask.execute();
|
|
176
|
+
}
|
|
177
|
+
picker.dispose();
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
protected async doPickerFirstLevel(picker: QuickPick<TaskEntry>): Promise<TaskEntry | undefined> {
|
|
181
|
+
picker.show();
|
|
182
|
+
const firstLevelPickerResult = await new Promise<TaskEntry | undefined | null>(resolve => {
|
|
183
|
+
picker.onDidAccept(async () => {
|
|
184
|
+
resolve(picker.selectedItems ? picker.selectedItems[0] : undefined);
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
return firstLevelPickerResult ?? undefined;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
protected async doSecondLevel(taskType: string): Promise<void> {
|
|
191
|
+
// Resolve Second level tasks based on selected TaskType
|
|
192
|
+
const isMulti = this.workspaceService.isMultiRootWorkspaceOpened;
|
|
193
|
+
const token = this.taskService.startUserAction();
|
|
194
|
+
const providedTasks = await this.taskService.getProvidedTasks(token, taskType);
|
|
195
|
+
const providedTasksItems = this.getItems(providedTasks, taskType + ' tasks', token, isMulti);
|
|
196
|
+
|
|
197
|
+
if (!providedTasksItems.length) {
|
|
198
|
+
providedTasksItems.push(({
|
|
199
|
+
label: NO_TASK_TO_RUN,
|
|
109
200
|
execute: () => this.configure()
|
|
110
201
|
}));
|
|
111
202
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
onDidTriggerItemButton: ({ item }) => this.onDidTriggerGearIcon(item)
|
|
115
|
-
});
|
|
203
|
+
|
|
204
|
+
this.quickInputService?.showQuickPick(providedTasksItems, { placeholder: CHOOSE_TASK });
|
|
116
205
|
}
|
|
117
206
|
|
|
118
207
|
attach(): void {
|
|
@@ -145,17 +234,26 @@ export class QuickOpenTask implements QuickAccessProvider {
|
|
|
145
234
|
label: 'No tasks found'
|
|
146
235
|
}));
|
|
147
236
|
}
|
|
148
|
-
this.quickInputService?.showQuickPick(this.items, { placeholder:
|
|
237
|
+
this.quickInputService?.showQuickPick(this.items, { placeholder: CHOOSE_TASK });
|
|
149
238
|
});
|
|
150
239
|
}
|
|
151
240
|
|
|
152
241
|
async configure(): Promise<void> {
|
|
153
|
-
this.
|
|
242
|
+
this.quickInputService?.pick(this.resolveItemsToConfigure(), { placeHolder: nls.localizeByDefault('Select a task to configure') }).
|
|
243
|
+
then(async item => {
|
|
244
|
+
if (item && 'execute' in item && typeof item.execute === 'function') {
|
|
245
|
+
item.execute();
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
protected async resolveItemsToConfigure(): Promise<QuickPickInput<QuickPickItemOrSeparator>[]> {
|
|
251
|
+
const items: Array<QuickPickInput<QuickPickItemOrSeparator>> = [];
|
|
154
252
|
const isMulti: boolean = this.workspaceService.isMultiRootWorkspaceOpened;
|
|
155
253
|
const token: number = this.taskService.startUserAction();
|
|
156
254
|
|
|
157
255
|
const configuredTasks = await this.taskService.getConfiguredTasks(token);
|
|
158
|
-
const providedTasks = await this.taskService.getProvidedTasks(token);
|
|
256
|
+
const providedTasks = await this.taskService.getProvidedTasks(token, '*');
|
|
159
257
|
|
|
160
258
|
// check if tasks.json exists. If not, display "Create tasks.json file from template"
|
|
161
259
|
// If tasks.json exists and empty, display 'Open tasks.json file'
|
|
@@ -163,7 +261,7 @@ export class QuickOpenTask implements QuickAccessProvider {
|
|
|
163
261
|
const groupedTasks = this.getGroupedTasksByWorkspaceFolder([...filteredConfiguredTasks, ...filteredProvidedTasks]);
|
|
164
262
|
if (groupedTasks.has(TaskScope.Global.toString())) {
|
|
165
263
|
const configs = groupedTasks.get(TaskScope.Global.toString())!;
|
|
166
|
-
|
|
264
|
+
items.push(
|
|
167
265
|
...configs.map(taskConfig => {
|
|
168
266
|
const item = new TaskConfigureQuickOpenItem(
|
|
169
267
|
token,
|
|
@@ -184,7 +282,7 @@ export class QuickOpenTask implements QuickAccessProvider {
|
|
|
184
282
|
const folderName = new URI(rootFolder).displayName;
|
|
185
283
|
if (groupedTasks.has(rootFolder)) {
|
|
186
284
|
const configs = groupedTasks.get(rootFolder.toString())!;
|
|
187
|
-
|
|
285
|
+
items.push(
|
|
188
286
|
...configs.map((taskConfig, index) => {
|
|
189
287
|
const item = new TaskConfigureQuickOpenItem(
|
|
190
288
|
token,
|
|
@@ -202,28 +300,28 @@ export class QuickOpenTask implements QuickAccessProvider {
|
|
|
202
300
|
} else {
|
|
203
301
|
const { configUri } = this.preferences.resolve('tasks', [], rootFolder);
|
|
204
302
|
const existTaskConfigFile = !!configUri;
|
|
205
|
-
|
|
303
|
+
items.push(({
|
|
206
304
|
label: existTaskConfigFile ? 'Open tasks.json file' : 'Create tasks.json file from template',
|
|
207
305
|
execute: () => {
|
|
208
306
|
setTimeout(() => this.taskConfigurationManager.openConfiguration(rootFolder));
|
|
209
307
|
}
|
|
210
308
|
}));
|
|
211
309
|
}
|
|
212
|
-
if (
|
|
213
|
-
|
|
310
|
+
if (items.length > 0) {
|
|
311
|
+
items.unshift({
|
|
214
312
|
type: 'separator',
|
|
215
313
|
label: isMulti ? folderName : ''
|
|
216
314
|
});
|
|
217
315
|
}
|
|
218
316
|
}
|
|
219
317
|
|
|
220
|
-
if (
|
|
221
|
-
|
|
318
|
+
if (items.length === 0) {
|
|
319
|
+
items.push(({
|
|
222
320
|
label: 'No tasks found'
|
|
223
321
|
}));
|
|
224
322
|
}
|
|
225
323
|
|
|
226
|
-
|
|
324
|
+
return items;
|
|
227
325
|
}
|
|
228
326
|
|
|
229
327
|
protected getTaskItems(): QuickPickItem[] {
|
|
@@ -297,9 +395,7 @@ export class QuickOpenTask implements QuickAccessProvider {
|
|
|
297
395
|
}
|
|
298
396
|
|
|
299
397
|
async getPicks(filter: string, token: CancellationToken): Promise<QuickPicks> {
|
|
300
|
-
|
|
301
|
-
await this.init();
|
|
302
|
-
}
|
|
398
|
+
await this.init();
|
|
303
399
|
return filterItems(this.items, filter);
|
|
304
400
|
}
|
|
305
401
|
|
|
@@ -317,8 +413,8 @@ export class QuickOpenTask implements QuickAccessProvider {
|
|
|
317
413
|
}
|
|
318
414
|
|
|
319
415
|
private getItems(tasks: TaskConfiguration[], groupLabel: string, token: number, isMulti: boolean):
|
|
320
|
-
|
|
321
|
-
const items:
|
|
416
|
+
TaskEntry[] {
|
|
417
|
+
const items: TaskEntry[] = tasks.map(task =>
|
|
322
418
|
new TaskRunQuickOpenItem(token, task, this.taskService, isMulti, this.taskDefinitionRegistry, this.taskNameResolver,
|
|
323
419
|
this.taskSourceResolver, this.taskConfigurationManager, [{
|
|
324
420
|
iconClass: 'codicon-gear',
|
|
@@ -81,6 +81,10 @@ export interface TaskProvider {
|
|
|
81
81
|
provideTasks(): Promise<TaskConfiguration[]>;
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
export interface WillResolveTaskProvider extends WaitUntilEvent {
|
|
85
|
+
taskType?: string
|
|
86
|
+
}
|
|
87
|
+
|
|
84
88
|
/**
|
|
85
89
|
* The {@link TaskResolverRegistry} is the common component for registration and provision of
|
|
86
90
|
* {@link TaskResolver}s. Theia will collect all {@link TaskContribution}s and invoke {@link TaskContribution#registerResolvers}
|
|
@@ -89,7 +93,7 @@ export interface TaskProvider {
|
|
|
89
93
|
@injectable()
|
|
90
94
|
export class TaskResolverRegistry {
|
|
91
95
|
|
|
92
|
-
protected readonly onWillProvideTaskResolverEmitter = new Emitter<
|
|
96
|
+
protected readonly onWillProvideTaskResolverEmitter = new Emitter<WillResolveTaskProvider>();
|
|
93
97
|
/**
|
|
94
98
|
* Emit when the registry provides a registered resolver. i.e. when the {@link TaskResolverRegistry#getResolver}
|
|
95
99
|
* function is called.
|
|
@@ -156,7 +160,7 @@ export class TaskResolverRegistry {
|
|
|
156
160
|
* @returns a promise of the registered `TaskResolver` or `undefined` if no resolver is registered for the given type.
|
|
157
161
|
*/
|
|
158
162
|
async getTaskResolver(type: string): Promise<TaskResolver | undefined> {
|
|
159
|
-
await WaitUntilEvent.fire(this.onWillProvideTaskResolverEmitter, {});
|
|
163
|
+
await WaitUntilEvent.fire(this.onWillProvideTaskResolverEmitter, { taskType: type });
|
|
160
164
|
return this.taskResolvers.get(type);
|
|
161
165
|
}
|
|
162
166
|
|
|
@@ -200,7 +204,7 @@ export class TaskResolverRegistry {
|
|
|
200
204
|
@injectable()
|
|
201
205
|
export class TaskProviderRegistry {
|
|
202
206
|
|
|
203
|
-
protected readonly onWillProvideTaskProviderEmitter = new Emitter<
|
|
207
|
+
protected readonly onWillProvideTaskProviderEmitter = new Emitter<WillResolveTaskProvider>();
|
|
204
208
|
/**
|
|
205
209
|
* Emit when the registry provides a registered task provider. i.e. when the {@link TaskProviderRegistry#getProvider}
|
|
206
210
|
* function is called.
|
|
@@ -229,6 +233,14 @@ export class TaskProviderRegistry {
|
|
|
229
233
|
};
|
|
230
234
|
}
|
|
231
235
|
|
|
236
|
+
/**
|
|
237
|
+
* Initiates activation of a TaskProvider with the given type
|
|
238
|
+
* @param type the task configuration type, '*' indicates, all providers.
|
|
239
|
+
*/
|
|
240
|
+
async activateProvider(type: string): Promise<void> {
|
|
241
|
+
await WaitUntilEvent.fire(this.onWillProvideTaskProviderEmitter, { taskType: type });
|
|
242
|
+
}
|
|
243
|
+
|
|
232
244
|
/**
|
|
233
245
|
* Retrieves the {@link TaskProvider} registered for the given type task configuration type.
|
|
234
246
|
* If there is already a `TaskProvider` registered for the specified type the registration will
|
|
@@ -238,17 +250,17 @@ export class TaskProviderRegistry {
|
|
|
238
250
|
* @returns a promise of the registered `TaskProvider`` or `undefined` if no provider is registered for the given type.
|
|
239
251
|
*/
|
|
240
252
|
async getProvider(type: string): Promise<TaskProvider | undefined> {
|
|
241
|
-
await
|
|
253
|
+
await this.activateProvider(type);
|
|
242
254
|
return this.providers.get(type);
|
|
243
255
|
}
|
|
244
256
|
|
|
245
257
|
/**
|
|
246
258
|
* Retrieve all registered {@link TaskProvider}s.
|
|
247
259
|
*
|
|
260
|
+
* Use {@link activateProvider} to control registration of providers as needed.
|
|
248
261
|
* @returns a promise of all registered {@link TaskProvider}s.
|
|
249
262
|
*/
|
|
250
263
|
async getProviders(): Promise<TaskProvider[]> {
|
|
251
|
-
await WaitUntilEvent.fire(this.onWillProvideTaskProviderEmitter, {});
|
|
252
264
|
return [...this.providers.values()];
|
|
253
265
|
}
|
|
254
266
|
}
|
|
@@ -403,11 +403,14 @@ export class TaskService implements TaskConfigurationClient {
|
|
|
403
403
|
}
|
|
404
404
|
|
|
405
405
|
/**
|
|
406
|
-
* Returns an array
|
|
406
|
+
* Returns an array that contains the task configurations provided by the task providers for the specified task type.
|
|
407
407
|
* @param token The cache token for the user interaction in progress
|
|
408
|
+
* @param type The task type (filter) associated to the returning TaskConfigurations
|
|
409
|
+
*
|
|
410
|
+
* '*' indicates all tasks regardless of the type
|
|
408
411
|
*/
|
|
409
|
-
getProvidedTasks(token: number): Promise<TaskConfiguration[]> {
|
|
410
|
-
return this.providedTaskConfigurations.getTasks(token);
|
|
412
|
+
getProvidedTasks(token: number, type?: string): Promise<TaskConfiguration[]> {
|
|
413
|
+
return this.providedTaskConfigurations.getTasks(token, type);
|
|
411
414
|
}
|
|
412
415
|
|
|
413
416
|
addRecentTasks(tasks: TaskConfiguration | TaskConfiguration[]): void {
|