Skip to content

Commit f68b1bd

Browse files
author
Benjamin Pasero
authored
Merge pull request microsoft#92907 from microsoft/ben/quick-access-anything
Quick access anything provider
2 parents 1e4fcba + 055553a commit f68b1bd

17 files changed

Lines changed: 821 additions & 71 deletions

File tree

src/vs/base/parts/quickinput/common/quickInput.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,22 +308,35 @@ export type QuickPickInput<T = IQuickPickItem> = T | IQuickPickSeparator;
308308

309309
export type IQuickPickItemWithResource = IQuickPickItem & { resource: URI | undefined };
310310

311-
export const quickPickItemScorerAccessor = new class implements IItemAccessor<IQuickPickItemWithResource> {
311+
export class QuickPickItemScorerAccessor implements IItemAccessor<IQuickPickItemWithResource> {
312+
313+
constructor(private options?: { skipDescription?: boolean, skipPath?: boolean }) { }
314+
312315
getItemLabel(entry: IQuickPickItemWithResource): string {
313316
return entry.label;
314317
}
315318

316319
getItemDescription(entry: IQuickPickItemWithResource): string | undefined {
320+
if (this.options?.skipDescription) {
321+
return undefined;
322+
}
323+
317324
return entry.description;
318325
}
319326

320327
getItemPath(entry: IQuickPickItemWithResource): string | undefined {
328+
if (this.options?.skipPath) {
329+
return undefined;
330+
}
331+
321332
if (entry.resource?.scheme === Schemas.file) {
322333
return entry.resource.fsPath;
323334
}
324335

325336
return entry.resource?.path;
326337
}
327-
};
338+
}
339+
340+
export const quickPickItemScorerAccessor = new QuickPickItemScorerAccessor();
328341

329342
//#endregion

src/vs/platform/quickinput/browser/commandsQuickAccess.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import { localize } from 'vs/nls';
77
import { IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput';
8-
import { PickerQuickAccessProvider, IPickerQuickAccessItem } from 'vs/platform/quickinput/browser/pickerQuickAccess';
8+
import { PickerQuickAccessProvider, IPickerQuickAccessItem, IPickerQuickAccessProviderOptions } from 'vs/platform/quickinput/browser/pickerQuickAccess';
99
import { distinct } from 'vs/base/common/arrays';
1010
import { CancellationToken } from 'vs/base/common/cancellation';
1111
import { DisposableStore, Disposable, IDisposable } from 'vs/base/common/lifecycle';
@@ -30,7 +30,7 @@ export interface ICommandQuickPick extends IPickerQuickAccessItem {
3030
commandAlias: string | undefined;
3131
}
3232

33-
export interface ICommandsQuickAccessOptions {
33+
export interface ICommandsQuickAccessOptions extends IPickerQuickAccessProviderOptions {
3434
showAlias: boolean;
3535
}
3636

@@ -43,14 +43,14 @@ export abstract class AbstractCommandsQuickAccessProvider extends PickerQuickAcc
4343
private readonly commandsHistory = this._register(this.instantiationService.createInstance(CommandsHistory));
4444

4545
constructor(
46-
private options: ICommandsQuickAccessOptions,
46+
protected options: ICommandsQuickAccessOptions,
4747
@IInstantiationService private readonly instantiationService: IInstantiationService,
4848
@IKeybindingService private readonly keybindingService: IKeybindingService,
4949
@ICommandService private readonly commandService: ICommandService,
5050
@ITelemetryService private readonly telemetryService: ITelemetryService,
5151
@INotificationService private readonly notificationService: INotificationService
5252
) {
53-
super(AbstractCommandsQuickAccessProvider.PREFIX);
53+
super(AbstractCommandsQuickAccessProvider.PREFIX, options);
5454
}
5555

5656
protected async getPicks(filter: string, disposables: DisposableStore, token: CancellationToken): Promise<Array<ICommandQuickPick | IQuickPickSeparator>> {

src/vs/platform/quickinput/browser/pickerQuickAccess.ts

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -53,17 +53,29 @@ export interface IPickerQuickAccessItem extends IQuickPickItem {
5353
trigger?(buttonIndex: number, keyMods: IKeyMods): TriggerAction | Promise<TriggerAction>;
5454
}
5555

56+
export interface IPickerQuickAccessProviderOptions {
57+
canAcceptInBackground?: boolean;
58+
}
59+
60+
export type FastAndSlowPicksType<T> = { picks: Array<T | IQuickPickSeparator>, additionalPicks: Promise<Array<T | IQuickPickSeparator>> };
61+
62+
function isFastAndSlowPicksType<T>(obj: unknown): obj is FastAndSlowPicksType<T> {
63+
const candidate = obj as FastAndSlowPicksType<T>;
64+
65+
return Array.isArray(candidate.picks) && candidate.additionalPicks instanceof Promise;
66+
}
67+
5668
export abstract class PickerQuickAccessProvider<T extends IPickerQuickAccessItem> extends Disposable implements IQuickAccessProvider {
5769

58-
constructor(private prefix: string) {
70+
constructor(private prefix: string, protected options?: IPickerQuickAccessProviderOptions) {
5971
super();
6072
}
6173

6274
provide(picker: IQuickPick<T>, token: CancellationToken): IDisposable {
6375
const disposables = new DisposableStore();
6476

65-
// Allow subclasses to configure picker
66-
this.configure(picker);
77+
// Apply options if any
78+
picker.canAcceptInBackground = !!this.options?.canAcceptInBackground;
6779

6880
// Disable filtering & sorting, we control the results
6981
picker.matchOnLabel = picker.matchOnDescription = picker.matchOnDetail = picker.sortByLabel = false;
@@ -79,9 +91,26 @@ export abstract class PickerQuickAccessProvider<T extends IPickerQuickAccessItem
7991
// Create new cancellation source for this run
8092
picksCts = new CancellationTokenSource(token);
8193

82-
// Collect picks and support both long running and short
94+
// Collect picks and support both long running and short or combined
8395
const res = this.getPicks(picker.value.substr(this.prefix.length).trim(), disposables.add(new DisposableStore()), picksCts.token);
84-
if (Array.isArray(res)) {
96+
if (isFastAndSlowPicksType(res)) {
97+
picker.items = res.picks;
98+
picker.busy = true;
99+
try {
100+
const additionalPicks = await res.additionalPicks;
101+
if (token.isCancellationRequested) {
102+
return;
103+
}
104+
105+
if (additionalPicks.length > 0) {
106+
picker.items = [...res.picks, ...additionalPicks];
107+
}
108+
} finally {
109+
if (!token.isCancellationRequested) {
110+
picker.busy = false;
111+
}
112+
}
113+
} else if (Array.isArray(res)) {
85114
picker.items = res;
86115
} else {
87116
picker.busy = true;
@@ -142,13 +171,6 @@ export abstract class PickerQuickAccessProvider<T extends IPickerQuickAccessItem
142171
return disposables;
143172
}
144173

145-
/**
146-
* Subclasses can override this method to configure the picker before showing it.
147-
*
148-
* @param picker the picker instance used for the quick access before it opens.
149-
*/
150-
protected configure(picker: IQuickPick<T>): void { }
151-
152174
/**
153175
* Returns an array of picks and separators as needed. If the picks are resolved
154176
* long running, the provided cancellation token should be used to cancel the
@@ -162,6 +184,7 @@ export abstract class PickerQuickAccessProvider<T extends IPickerQuickAccessItem
162184
* up when the picker closes.
163185
* @param token for long running tasks, implementors need to check on cancellation
164186
* through this token.
187+
* @returns the picks either directly, as promise or combined fast and slow results.
165188
*/
166-
protected abstract getPicks(filter: string, disposables: DisposableStore, token: CancellationToken): Array<T | IQuickPickSeparator> | Promise<Array<T | IQuickPickSeparator>>;
189+
protected abstract getPicks(filter: string, disposables: DisposableStore, token: CancellationToken): Array<T | IQuickPickSeparator> | Promise<Array<T | IQuickPickSeparator>> | { picks: Array<T | IQuickPickSeparator>, additionalPicks: Promise<Array<T | IQuickPickSeparator>> };
167190
}

src/vs/workbench/browser/parts/editor/editorQuickAccess.ts

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6+
import 'vs/css!./media/editorquickaccess';
67
import { localize } from 'vs/nls';
7-
import { IQuickPickSeparator, quickPickItemScorerAccessor, IQuickPickItemWithResource, IQuickPick } from 'vs/platform/quickinput/common/quickInput';
8+
import { IQuickPickSeparator, quickPickItemScorerAccessor, IQuickPickItemWithResource } from 'vs/platform/quickinput/common/quickInput';
89
import { PickerQuickAccessProvider, IPickerQuickAccessItem, TriggerAction } from 'vs/platform/quickinput/browser/pickerQuickAccess';
910
import { IEditorGroupsService, GroupsOrder } from 'vs/workbench/services/editor/common/editorGroupsService';
1011
import { EditorsOrder, IEditorIdentifier, toResource, SideBySideEditor } from 'vs/workbench/common/editor';
@@ -25,18 +26,14 @@ export abstract class BaseEditorQuickAccessProvider extends PickerQuickAccessPro
2526
@IModelService private readonly modelService: IModelService,
2627
@IModeService private readonly modeService: IModeService
2728
) {
28-
super(prefix);
29-
}
30-
31-
protected configure(picker: IQuickPick<IEditorQuickPickItem>): void {
32-
33-
// Allow to open editors in background without closing picker
34-
picker.canAcceptInBackground = true;
29+
super(prefix, { canAcceptInBackground: true });
3530
}
3631

3732
protected getPicks(filter: string): Array<IEditorQuickPickItem | IQuickPickSeparator> {
3833
const query = prepareQuery(filter);
3934
const scorerCache = Object.create(null);
35+
36+
// Filtering
4037
const filteredEditorEntries = this.doGetEditorPickItems().filter(entry => {
4138
if (!query.value) {
4239
return true;
@@ -105,7 +102,7 @@ export abstract class BaseEditorQuickAccessProvider extends PickerQuickAccessPro
105102
buttonsAlwaysVisible: isDirty,
106103
buttons: [
107104
{
108-
iconClass: isDirty ? 'codicon-circle-filled' : 'codicon-close',
105+
iconClass: isDirty ? 'dirty-editor codicon-circle-filled' : 'codicon-close',
109106
tooltip: localize('closeEditor', "Close Editor")
110107
}
111108
],

src/vs/workbench/contrib/files/browser/media/fileactions.css renamed to src/vs/workbench/browser/parts/editor/media/editorquickaccess.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
.open-editors .monaco-list .monaco-list-row.dirty:not(:hover) > .monaco-action-bar .codicon-close::before {
7-
content: "\ea71";
6+
.quick-input-list .quick-input-list-entry.has-actions:hover .quick-input-list-entry-action-bar .action-label.dirty-editor::before {
7+
content: "\ea76"; /* Close icon flips between black dot and "X" for dirty open editors */
88
}

src/vs/workbench/contrib/files/browser/fileActions.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
import 'vs/css!./media/fileactions';
76
import * as nls from 'vs/nls';
87
import { isWindows, isWeb } from 'vs/base/common/platform';
98
import * as extpath from 'vs/base/common/extpath';

src/vs/workbench/contrib/files/browser/views/media/openeditors.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@
2525
justify-content: center;
2626
}
2727

28+
.open-editors .monaco-list .monaco-list-row.dirty:not(:hover) > .monaco-action-bar .codicon-close::before {
29+
content: "\ea71"; /* Close icon flips between black dot and "X" for dirty open editors */
30+
}
31+
2832
.open-editors .monaco-list .monaco-list-row > .monaco-action-bar .action-close-all-files,
2933
.open-editors .monaco-list .monaco-list-row > .monaco-action-bar .save-all {
3034
width: 23px;

0 commit comments

Comments
 (0)