Skip to content

Commit 6ce1ad6

Browse files
authored
allow more args in run task (microsoft#154854)
1 parent 2f5b562 commit 6ce1ad6

File tree

3 files changed

+98
-31
lines changed

3 files changed

+98
-31
lines changed

src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts

Lines changed: 84 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ import { ITextEditorSelection, TextEditorSelectionRevealType } from 'vs/platform
7878
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
7979
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
8080
import { IViewsService, IViewDescriptorService } from 'vs/workbench/common/views';
81-
import { isWorkspaceFolder, ITaskQuickPickEntry, QUICKOPEN_DETAIL_CONFIG, TaskQuickPick, QUICKOPEN_SKIP_CONFIG, configureTaskIcon } from 'vs/workbench/contrib/tasks/browser/taskQuickPick';
81+
import { isWorkspaceFolder, ITaskQuickPickEntry, QUICKOPEN_DETAIL_CONFIG, TaskQuickPick, QUICKOPEN_SKIP_CONFIG, configureTaskIcon, ITaskTwoLevelQuickPickEntry } from 'vs/workbench/contrib/tasks/browser/taskQuickPick';
8282
import { ILogService } from 'vs/platform/log/common/log';
8383
import { once } from 'vs/base/common/functional';
8484
import { IThemeService, ThemeIcon } from 'vs/platform/theme/common/themeService';
@@ -347,7 +347,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
347347
return this.inTerminal();
348348
}
349349

350-
private _registerCommands(): void {
350+
private async _registerCommands(): Promise<void> {
351351
CommandsRegistry.registerCommand({
352352
id: 'workbench.action.tasks.runTask',
353353
handler: async (accessor, arg) => {
@@ -359,8 +359,30 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
359359
description: 'Run Task',
360360
args: [{
361361
name: 'args',
362+
isOptional: true,
363+
description: nls.localize('runTask.arg', "Filters the tasks shown in the quickpick"),
362364
schema: {
363-
'type': 'string',
365+
anyOf: [
366+
{
367+
type: 'string',
368+
description: nls.localize('runTask.label', "The task's label or a term to filter by")
369+
},
370+
{
371+
type: 'object',
372+
properties: {
373+
type: {
374+
type: 'string',
375+
description: nls.localize('runTask.type', "The contributed task type"),
376+
enum: Array.from(this._providerTypes.values()).map(provider => provider)
377+
},
378+
taskName: {
379+
type: 'string',
380+
description: nls.localize('runTask.taskName', "The task's label or a term to filter by"),
381+
enum: await this.tasks().then((tasks) => tasks.map(t => t._label))
382+
}
383+
}
384+
}
385+
]
364386
}
365387
}]
366388
}
@@ -2521,11 +2543,11 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
25212543
return entries;
25222544
}
25232545

2524-
private async _showTwoLevelQuickPick(placeHolder: string, defaultEntry?: ITaskQuickPickEntry) {
2525-
return TaskQuickPick.show(this, this._configurationService, this._quickInputService, this._notificationService, this._dialogService, this._themeService, placeHolder, defaultEntry);
2546+
private async _showTwoLevelQuickPick(placeHolder: string, defaultEntry?: ITaskQuickPickEntry, filter?: string) {
2547+
return TaskQuickPick.show(this, this._configurationService, this._quickInputService, this._notificationService, this._dialogService, this._themeService, placeHolder, defaultEntry, filter);
25262548
}
25272549

2528-
private async _showQuickPick(tasks: Promise<Task[]> | Task[], placeHolder: string, defaultEntry?: ITaskQuickPickEntry, group: boolean = false, sort: boolean = false, selectedEntry?: ITaskQuickPickEntry, additionalEntries?: ITaskQuickPickEntry[]): Promise<ITaskQuickPickEntry | undefined | null> {
2550+
private async _showQuickPick(tasks: Promise<Task[]> | Task[], placeHolder: string, defaultEntry?: ITaskQuickPickEntry, group: boolean = false, sort: boolean = false, selectedEntry?: ITaskQuickPickEntry, additionalEntries?: ITaskQuickPickEntry[], filter?: string): Promise<ITaskQuickPickEntry | undefined | null> {
25292551
const tokenSource = new CancellationTokenSource();
25302552
const cancellationToken: CancellationToken = tokenSource.token;
25312553
const createEntries = new Promise<QuickPickInput<ITaskQuickPickEntry>[]>((resolve) => {
@@ -2564,7 +2586,6 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
25642586
const picker: IQuickPick<ITaskQuickPickEntry> = this._quickInputService.createQuickPick();
25652587
picker.placeholder = placeHolder;
25662588
picker.matchOnDescription = true;
2567-
25682589
picker.onDidTriggerItemButton(context => {
25692590
const task = context.item.task;
25702591
this._quickInputService.cancel();
@@ -2580,7 +2601,9 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
25802601
picker.items = entries;
25812602
});
25822603
picker.show();
2583-
2604+
if (filter) {
2605+
picker.value = filter;
2606+
}
25842607
return new Promise<ITaskQuickPickEntry | undefined | null>(resolve => {
25852608
this._register(picker.onDidAccept(async () => {
25862609
let selection = picker.selectedItems ? picker.selectedItems[0] : undefined;
@@ -2654,12 +2677,20 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
26542677
})) === true;
26552678
}
26562679

2657-
private _runTaskCommand(arg?: any): void {
2680+
private async _runTaskCommand(filter?: { type?: string; taskName?: string } | string): Promise<void> {
26582681
if (!this._canRunCommand()) {
26592682
return;
26602683
}
2661-
const identifier = this._getTaskIdentifier(arg);
2662-
if (identifier !== undefined) {
2684+
2685+
let typeFilter: boolean = false;
2686+
if (filter && typeof filter !== 'string') {
2687+
// name takes precedence
2688+
typeFilter = !filter?.taskName && !!filter?.type;
2689+
filter = filter?.taskName || filter?.type;
2690+
}
2691+
2692+
const taskIdentifier: KeyedTaskIdentifier | undefined | string = this._getTaskIdentifier(filter);
2693+
if (taskIdentifier) {
26632694
this._getGroupedTasks().then(async (grouped) => {
26642695
const resolver = this._createResolver(grouped);
26652696
const folderURIs: (URI | string)[] = this._contextService.getWorkspace().folders.map(folder => folder.uri);
@@ -2668,15 +2699,15 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
26682699
}
26692700
folderURIs.push(USER_TASKS_GROUP_KEY);
26702701
for (const uri of folderURIs) {
2671-
const task = await resolver.resolve(uri, identifier);
2702+
const task = await resolver.resolve(uri, taskIdentifier);
26722703
if (task) {
26732704
this.run(task).then(undefined, reason => {
26742705
// eat the error, it has already been surfaced to the user and we don't care about it here
26752706
});
26762707
return;
26772708
}
26782709
}
2679-
this._doRunTaskCommand(grouped.all());
2710+
this._doRunTaskCommand(grouped.all(), typeof taskIdentifier === 'string' ? taskIdentifier : undefined, typeFilter);
26802711
}, () => {
26812712
this._doRunTaskCommand();
26822713
});
@@ -2716,7 +2747,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
27162747
return { tasks, grouped };
27172748
}
27182749

2719-
private _doRunTaskCommand(tasks?: Task[]): void {
2750+
private _doRunTaskCommand(tasks?: Task[], filter?: string, typeFilter?: boolean): void {
27202751
const pickThen = (task: Task | undefined | null) => {
27212752
if (task === undefined) {
27222753
return;
@@ -2732,28 +2763,58 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
27322763

27332764
const placeholder = nls.localize('TaskService.pickRunTask', 'Select the task to run');
27342765

2735-
this._showIgnoredFoldersMessage().then(() => {
2766+
this._showIgnoredFoldersMessage().then(async () => {
27362767
if (this._configurationService.getValue(USE_SLOW_PICKER)) {
27372768
let taskResult: { tasks: Promise<Task[]>; grouped: Promise<TaskMap> } | undefined = undefined;
27382769
if (!tasks) {
27392770
taskResult = this._tasksAndGroupedTasks();
27402771
}
2772+
if (filter && typeFilter) {
2773+
const picker: IQuickPick<ITaskTwoLevelQuickPickEntry> = this._quickInputService.createQuickPick();
2774+
picker.placeholder = nls.localize('TaskService.pickRunTask', 'Select the task to run');
2775+
picker.matchOnDescription = true;
2776+
picker.ignoreFocusOut = false;
2777+
const taskQuickPick = new TaskQuickPick(this, this._configurationService, this._quickInputService, this._notificationService, this._themeService, this._dialogService);
2778+
const result = await taskQuickPick.doPickerSecondLevel(picker, filter);
2779+
if (result?.task) {
2780+
pickThen(result.task as Task);
2781+
taskQuickPick.dispose();
2782+
}
2783+
return;
2784+
}
27412785
this._showQuickPick(tasks ? tasks : taskResult!.tasks, placeholder,
27422786
{
27432787
label: '$(plus) ' + nls.localize('TaskService.noEntryToRun', 'Configure a Task'),
27442788
task: null
27452789
},
2746-
true).
2790+
true, false, undefined, undefined, typeof filter === 'string' ? filter : undefined).
27472791
then((entry) => {
27482792
return pickThen(entry ? entry.task : undefined);
27492793
});
27502794
} else {
2751-
this._showTwoLevelQuickPick(placeholder,
2752-
{
2753-
label: '$(plus) ' + nls.localize('TaskService.noEntryToRun', 'Configure a Task'),
2754-
task: null
2755-
}).
2756-
then(pickThen);
2795+
if (filter && typeFilter) {
2796+
const picker: IQuickPick<ITaskTwoLevelQuickPickEntry> = this._quickInputService.createQuickPick();
2797+
picker.placeholder = nls.localize('TaskService.pickRunTask', 'Select the task to run');
2798+
picker.matchOnDescription = true;
2799+
picker.ignoreFocusOut = false;
2800+
const taskQuickPick = new TaskQuickPick(this, this._configurationService, this._quickInputService, this._notificationService, this._themeService, this._dialogService);
2801+
const result = await taskQuickPick.doPickerSecondLevel(picker, filter);
2802+
if (result?.task) {
2803+
pickThen(result.task as Task);
2804+
picker.dispose();
2805+
taskQuickPick.dispose();
2806+
return;
2807+
} else {
2808+
return;
2809+
}
2810+
} else {
2811+
this._showTwoLevelQuickPick(placeholder,
2812+
{
2813+
label: '$(plus) ' + nls.localize('TaskService.noEntryToRun', 'Configure a Task'),
2814+
task: null
2815+
}, typeof filter === 'string' ? filter : undefined).
2816+
then(pickThen);
2817+
}
27572818
}
27582819
});
27592820
}
@@ -3055,7 +3116,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
30553116
}
30563117
}
30573118

3058-
private _getTaskIdentifier(arg?: any): string | KeyedTaskIdentifier | undefined {
3119+
private _getTaskIdentifier(arg?: string | ITaskIdentifier): string | KeyedTaskIdentifier | undefined {
30593120
let result: string | KeyedTaskIdentifier | undefined = undefined;
30603121
if (Types.isString(arg)) {
30613122
result = arg;

src/vs/workbench/contrib/tasks/browser/taskQuickPick.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -218,12 +218,15 @@ export class TaskQuickPick extends Disposable {
218218
return undefined;
219219
}
220220

221-
public async show(placeHolder: string, defaultEntry?: ITaskQuickPickEntry, startAtType?: string): Promise<Task | undefined | null> {
221+
public async show(placeHolder: string, defaultEntry?: ITaskQuickPickEntry, startAtType?: string, filter?: string): Promise<Task | undefined | null> {
222222
const picker: IQuickPick<ITaskTwoLevelQuickPickEntry> = this._quickInputService.createQuickPick();
223223
picker.placeholder = placeHolder;
224224
picker.matchOnDescription = true;
225225
picker.ignoreFocusOut = false;
226226
picker.show();
227+
if (filter) {
228+
picker.value = filter;
229+
}
227230

228231
picker.onDidTriggerItemButton(async (context) => {
229232
const task = context.item.task;
@@ -268,7 +271,7 @@ export class TaskQuickPick extends Disposable {
268271
do {
269272
if (Types.isString(firstLevelTask)) {
270273
// Proceed to second level of quick pick
271-
const selectedEntry = await this._doPickerSecondLevel(picker, firstLevelTask);
274+
const selectedEntry = await this.doPickerSecondLevel(picker, firstLevelTask);
272275
if (selectedEntry && !selectedEntry.settingType && selectedEntry.task === null) {
273276
// The user has chosen to go back to the first level
274277
firstLevelTask = await this._doPickerFirstLevel(picker, (await this.getTopLevelEntries(defaultEntry)).entries);
@@ -302,7 +305,7 @@ export class TaskQuickPick extends Disposable {
302305
return firstLevelPickerResult?.task;
303306
}
304307

305-
private async _doPickerSecondLevel(picker: IQuickPick<ITaskTwoLevelQuickPickEntry>, type: string) {
308+
public async doPickerSecondLevel(picker: IQuickPick<ITaskTwoLevelQuickPickEntry>, type: string) {
306309
picker.busy = true;
307310
if (type === SHOW_ALL) {
308311
const items = (await this._taskService.tasks()).filter(t => !t.configurationProperties.hide).sort((a, b) => this._sorter.compare(a, b)).map(task => this._createTaskEntry(task));
@@ -312,13 +315,13 @@ export class TaskQuickPick extends Disposable {
312315
picker.value = '';
313316
picker.items = await this._getEntriesForProvider(type);
314317
}
318+
picker.show();
315319
picker.busy = false;
316320
const secondLevelPickerResult = await new Promise<ITaskTwoLevelQuickPickEntry | undefined | null>(resolve => {
317321
Event.once(picker.onDidAccept)(async () => {
318322
resolve(picker.selectedItems ? picker.selectedItems[0] : undefined);
319323
});
320324
});
321-
322325
return secondLevelPickerResult;
323326
}
324327

@@ -398,8 +401,8 @@ export class TaskQuickPick extends Disposable {
398401

399402
static async show(taskService: ITaskService, configurationService: IConfigurationService,
400403
quickInputService: IQuickInputService, notificationService: INotificationService,
401-
dialogService: IDialogService, themeService: IThemeService, placeHolder: string, defaultEntry?: ITaskQuickPickEntry) {
404+
dialogService: IDialogService, themeService: IThemeService, placeHolder: string, defaultEntry?: ITaskQuickPickEntry, filter?: string) {
402405
const taskQuickPick = new TaskQuickPick(taskService, configurationService, quickInputService, notificationService, themeService, dialogService);
403-
return taskQuickPick.show(placeHolder, defaultEntry);
406+
return taskQuickPick.show(placeHolder, defaultEntry, undefined, filter);
404407
}
405408
}

src/vs/workbench/contrib/tasks/electron-sandbox/taskService.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import { IWorkspaceTrustManagementService, IWorkspaceTrustRequestService } from
4444
import { ITerminalProfileResolverService } from 'vs/workbench/contrib/terminal/common/terminal';
4545
import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite';
4646
import { IThemeService } from 'vs/platform/theme/common/themeService';
47+
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
4748

4849
interface IWorkspaceFolderConfigurationResult {
4950
workspaceFolder: IWorkspaceFolder;
@@ -85,7 +86,8 @@ export class TaskService extends AbstractTaskService {
8586
@IWorkspaceTrustRequestService workspaceTrustRequestService: IWorkspaceTrustRequestService,
8687
@IWorkspaceTrustManagementService workspaceTrustManagementService: IWorkspaceTrustManagementService,
8788
@ILogService logService: ILogService,
88-
@IThemeService themeService: IThemeService) {
89+
@IThemeService themeService: IThemeService,
90+
@IInstantiationService instantiationService: IInstantiationService) {
8991
super(configurationService,
9092
markerService,
9193
outputService,
@@ -118,7 +120,8 @@ export class TaskService extends AbstractTaskService {
118120
workspaceTrustRequestService,
119121
workspaceTrustManagementService,
120122
logService,
121-
themeService);
123+
themeService,
124+
);
122125
this._register(lifecycleService.onBeforeShutdown(event => event.veto(this.beforeShutdown(), 'veto.tasks')));
123126
}
124127

0 commit comments

Comments
 (0)