Skip to content

Commit 0cc0673

Browse files
author
Benjamin Pasero
committed
quick access - fix some issues
1 parent 4aac842 commit 0cc0673

8 files changed

Lines changed: 91 additions & 52 deletions

File tree

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
460460
set items(items: Array<T | IQuickPickSeparator>) {
461461
this._items = items;
462462
this.itemsUpdated = true;
463-
if (this._items.length === 0) {
463+
if (items.length === 0) {
464464
// quick-navigate requires at least 1 item
465465
this._quickNavigate = undefined;
466466
}
@@ -818,11 +818,12 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
818818
if (!this.visible) {
819819
return;
820820
}
821-
dom.toggleClass(this.ui.container, 'quick-navigate-mode', !!this._quickNavigate);
821+
const isQuickNavigating = !!this._quickNavigate && this._items.length > 0; // quick nav requires at least 1 item
822+
dom.toggleClass(this.ui.container, 'quick-navigate-mode', isQuickNavigating);
822823
const ok = this.ok === 'default' ? this.canSelectMany : this.ok;
823824
const visibilities: Visibilities = this.canSelectMany ?
824-
{ title: !!this.title || !!this.step, description: !!this.description, checkAll: true, inputBox: !this._quickNavigate, progressBar: !this._quickNavigate, visibleCount: true, count: true, ok, list: true, message: !!this.validationMessage, customButton: this.customButton } :
825-
{ title: !!this.title || !!this.step, description: !!this.description, inputBox: !this._quickNavigate, progressBar: !this._quickNavigate, visibleCount: true, list: true, message: !!this.validationMessage, customButton: this.customButton, ok };
825+
{ title: !!this.title || !!this.step, description: !!this.description, checkAll: true, inputBox: !isQuickNavigating, progressBar: !isQuickNavigating, visibleCount: true, count: true, ok, list: true, message: !!this.validationMessage, customButton: this.customButton } :
826+
{ title: !!this.title || !!this.step, description: !!this.description, inputBox: !isQuickNavigating, progressBar: !isQuickNavigating, visibleCount: true, list: true, message: !!this.validationMessage, customButton: this.customButton, ok };
826827
this.ui.setVisibilities(visibilities);
827828
super.update();
828829
if (this.ui.inputBox.value !== this.value) {
@@ -850,7 +851,7 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
850851
this.ui.checkAll.checked = this.ui.list.getAllVisibleChecked();
851852
this.ui.visibleCount.setCount(this.ui.list.getVisibleCount());
852853
this.ui.count.setCount(this.ui.list.getCheckedCount());
853-
if (this._quickNavigate && previousItemCount === 0 && this.items.length > 1) {
854+
if (isQuickNavigating && previousItemCount === 0) {
854855
// quick navigate: automatically focus the second entry
855856
// so that upon release the item is picked directly
856857
this.ui.list.focus(QuickInputListFocus.Second);

src/vs/base/parts/quickinput/browser/quickInputList.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -492,10 +492,15 @@ export class QuickInputList {
492492
if ((what === QuickInputListFocus.Next || what === QuickInputListFocus.NextPage) && this.list.getFocus()[0] === this.list.length - 1) {
493493
what = QuickInputListFocus.First;
494494
}
495+
495496
if ((what === QuickInputListFocus.Previous || what === QuickInputListFocus.PreviousPage) && this.list.getFocus()[0] === 0) {
496497
what = QuickInputListFocus.Last;
497498
}
498499

500+
if (what === QuickInputListFocus.Second && this.list.length < 2) {
501+
what = QuickInputListFocus.First;
502+
}
503+
499504
switch (what) {
500505
case QuickInputListFocus.First:
501506
this.list.focusFirst();
@@ -520,7 +525,10 @@ export class QuickInputList {
520525
break;
521526
}
522527

523-
this.list.reveal(this.list.getFocus()[0]);
528+
const focused = this.list.getFocus()[0];
529+
if (focused) {
530+
this.list.reveal(focused);
531+
}
524532
}
525533

526534
clearFocus() {

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

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import { localize } from 'vs/nls';
77
import { IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput';
88
import { PickerQuickAccessProvider, IPickerQuickAccessItem, IPickerQuickAccessProviderOptions } from 'vs/platform/quickinput/browser/pickerQuickAccess';
9-
import { distinct } from 'vs/base/common/arrays';
109
import { CancellationToken } from 'vs/base/common/cancellation';
1110
import { DisposableStore, Disposable, IDisposable } from 'vs/base/common/lifecycle';
1211
import { or, matchesPrefix, matchesWords, matchesContiguousSubString } from 'vs/base/common/filters';
@@ -22,8 +21,6 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
2221
import { isPromiseCanceledError } from 'vs/base/common/errors';
2322
import { INotificationService } from 'vs/platform/notification/common/notification';
2423
import { toErrorMessage } from 'vs/base/common/errorMessage';
25-
import { isFirefox } from 'vs/base/browser/browser';
26-
import { timeout } from 'vs/base/common/async';
2724

2825
export interface ICommandQuickPick extends IPickerQuickAccessItem {
2926
commandId: string;
@@ -74,12 +71,9 @@ export abstract class AbstractCommandsQuickAccessProvider extends PickerQuickAcc
7471
}
7572
}
7673

77-
// Remove duplicates
78-
const distinctCommandPicks = distinct(filteredCommandPicks, pick => `${pick.label}${pick.commandId}`);
79-
8074
// Add description to commands that have duplicate labels
8175
const mapLabelToCommand = new Map<string, ICommandQuickPick>();
82-
for (const commandPick of distinctCommandPicks) {
76+
for (const commandPick of filteredCommandPicks) {
8377
const existingCommandForLabel = mapLabelToCommand.get(commandPick.label);
8478
if (existingCommandForLabel) {
8579
commandPick.description = commandPick.commandId;
@@ -90,7 +84,7 @@ export abstract class AbstractCommandsQuickAccessProvider extends PickerQuickAcc
9084
}
9185

9286
// Sort by MRU order and fallback to name otherwise
93-
distinctCommandPicks.sort((commandPickA, commandPickB) => {
87+
filteredCommandPicks.sort((commandPickA, commandPickB) => {
9488
const commandACounter = this.commandsHistory.peek(commandPickA.commandId);
9589
const commandBCounter = this.commandsHistory.peek(commandPickB.commandId);
9690

@@ -113,8 +107,8 @@ export abstract class AbstractCommandsQuickAccessProvider extends PickerQuickAcc
113107
const commandPicks: Array<ICommandQuickPick | IQuickPickSeparator> = [];
114108

115109
let addSeparator = false;
116-
for (let i = 0; i < distinctCommandPicks.length; i++) {
117-
const commandPick = distinctCommandPicks[i];
110+
for (let i = 0; i < filteredCommandPicks.length; i++) {
111+
const commandPick = filteredCommandPicks[i];
118112
const keybinding = this.keybindingService.lookupKeybinding(commandPick.commandId);
119113
const ariaLabel = keybinding ?
120114
localize('commandPickAriaLabelWithKeybinding', "{0}, {1}, commands picker", commandPick.label, keybinding.getAriaLabel()) :
@@ -143,13 +137,6 @@ export abstract class AbstractCommandsQuickAccessProvider extends PickerQuickAcc
143137
// Add to history
144138
this.commandsHistory.push(commandPick.commandId);
145139

146-
if (!isFirefox) {
147-
// Use a timeout to give the quick open widget a chance to close itself first
148-
// Firefox: since the browser is quite picky for certain commands, we do not
149-
// use a timeout (https://github.com/microsoft/vscode/issues/83288)
150-
await timeout(50);
151-
}
152-
153140
// Telementry
154141
this.telemetryService.publicLog2<WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification>('workbenchActionExecuted', {
155142
id: commandPick.commandId,

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ export class HelpQuickAccessProvider implements IQuickAccessProvider {
6666
const editorProviders: IHelpQuickAccessPickItem[] = [];
6767

6868
for (const provider of this.registry.getQuickAccessProviders().sort((providerA, providerB) => providerA.prefix.localeCompare(providerB.prefix))) {
69+
if (provider.prefix === HelpQuickAccessProvider.PREFIX) {
70+
continue; // exclude help which is already active
71+
}
72+
6973
for (const helpEntry of provider.helpEntries) {
7074
const prefix = helpEntry.prefix || provider.prefix;
7175
const label = prefix || '\u2026' /* ... */;

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

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,39 @@
55

66
import 'vs/css!./media/editorquickaccess';
77
import { localize } from 'vs/nls';
8-
import { IQuickPickSeparator, quickPickItemScorerAccessor, IQuickPickItemWithResource } from 'vs/platform/quickinput/common/quickInput';
8+
import { IQuickPickSeparator, quickPickItemScorerAccessor, IQuickPickItemWithResource, IQuickPick } from 'vs/platform/quickinput/common/quickInput';
99
import { PickerQuickAccessProvider, IPickerQuickAccessItem, TriggerAction } from 'vs/platform/quickinput/browser/pickerQuickAccess';
1010
import { IEditorGroupsService, GroupsOrder } from 'vs/workbench/services/editor/common/editorGroupsService';
1111
import { EditorsOrder, IEditorIdentifier, toResource, SideBySideEditor } from 'vs/workbench/common/editor';
1212
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
1313
import { IModelService } from 'vs/editor/common/services/modelService';
1414
import { IModeService } from 'vs/editor/common/services/modeService';
1515
import { getIconClasses } from 'vs/editor/common/services/getIconClasses';
16-
import { prepareQuery, scoreItem, compareItemsByScore } from 'vs/base/common/fuzzyScorer';
16+
import { prepareQuery, scoreItem, compareItemsByScore, ScorerCache } from 'vs/base/common/fuzzyScorer';
17+
import { CancellationToken } from 'vs/base/common/cancellation';
18+
import { IDisposable } from 'vs/base/common/lifecycle';
1719

1820
interface IEditorQuickPickItem extends IQuickPickItemWithResource, IEditorIdentifier, IPickerQuickAccessItem { }
1921

2022
export abstract class BaseEditorQuickAccessProvider extends PickerQuickAccessProvider<IEditorQuickPickItem> {
2123

24+
private readonly pickState = new class {
25+
26+
scorerCache: ScorerCache = Object.create(null);
27+
isQuickNavigating: boolean | undefined = undefined;
28+
29+
reset(isQuickNavigating: boolean): void {
30+
31+
// Caches
32+
if (!isQuickNavigating) {
33+
this.scorerCache = Object.create(null);
34+
}
35+
36+
// Other
37+
this.isQuickNavigating = isQuickNavigating;
38+
}
39+
};
40+
2241
constructor(
2342
prefix: string,
2443
@IEditorGroupsService protected readonly editorGroupService: IEditorGroupsService,
@@ -29,9 +48,17 @@ export abstract class BaseEditorQuickAccessProvider extends PickerQuickAccessPro
2948
super(prefix, { canAcceptInBackground: true });
3049
}
3150

51+
provide(picker: IQuickPick<IEditorQuickPickItem>, token: CancellationToken): IDisposable {
52+
53+
// Reset the pick state for this run
54+
this.pickState.reset(!!picker.quickNavigate);
55+
56+
// Start picker
57+
return super.provide(picker, token);
58+
}
59+
3260
protected getPicks(filter: string): Array<IEditorQuickPickItem | IQuickPickSeparator> {
3361
const query = prepareQuery(filter);
34-
const scorerCache = Object.create(null);
3562

3663
// Filtering
3764
const filteredEditorEntries = this.doGetEditorPickItems().filter(entry => {
@@ -40,7 +67,7 @@ export abstract class BaseEditorQuickAccessProvider extends PickerQuickAccessPro
4067
}
4168

4269
// Score on label and description
43-
const itemScore = scoreItem(entry, query, true, quickPickItemScorerAccessor, scorerCache);
70+
const itemScore = scoreItem(entry, query, true, quickPickItemScorerAccessor, this.pickState.scorerCache);
4471
if (!itemScore.score) {
4572
return false;
4673
}
@@ -59,7 +86,7 @@ export abstract class BaseEditorQuickAccessProvider extends PickerQuickAccessPro
5986
return groups.indexOf(entryA.groupId) - groups.indexOf(entryB.groupId); // older groups first
6087
}
6188

62-
return compareItemsByScore(entryA, entryB, query, true, quickPickItemScorerAccessor, scorerCache);
89+
return compareItemsByScore(entryA, entryB, query, true, quickPickItemScorerAccessor, this.pickState.scorerCache);
6390
});
6491
}
6592

@@ -99,13 +126,19 @@ export abstract class BaseEditorQuickAccessProvider extends PickerQuickAccessPro
99126
description: editor.getDescription(),
100127
iconClasses: getIconClasses(this.modelService, this.modeService, resource),
101128
italic: !this.editorGroupService.getGroup(groupId)?.isPinned(editor),
102-
buttons: [
103-
{
104-
iconClass: isDirty ? 'dirty-editor codicon-circle-filled' : 'codicon-close',
105-
tooltip: localize('closeEditor', "Close Editor"),
106-
alwaysVisible: isDirty
129+
buttons: (() => {
130+
if (this.pickState.isQuickNavigating) {
131+
return undefined; // no actions when quick navigating
107132
}
108-
],
133+
134+
return [
135+
{
136+
iconClass: isDirty ? 'dirty-editor codicon-circle-filled' : 'codicon-close',
137+
tooltip: localize('closeEditor', "Close Editor"),
138+
alwaysVisible: isDirty
139+
}
140+
];
141+
})(),
109142
trigger: async () => {
110143
await this.editorGroupService.getGroup(groupId)?.closeEditor(editor, { preserveFocus: true });
111144

src/vs/workbench/browser/quickopen.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ export class QuickOpenAction extends Action {
325325
id: string,
326326
label: string,
327327
prefix: string,
328-
@IQuickOpenService private readonly quickOpenService: IQuickOpenService
328+
@IQuickOpenService protected readonly quickOpenService: IQuickOpenService
329329
) {
330330
super(id, label);
331331

src/vs/workbench/contrib/quickopen/browser/gotoLineHandler.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,22 +31,18 @@ export class GotoLineAction extends QuickOpenAction {
3131
static readonly LABEL = nls.localize('gotoLine', "Go to Line...");
3232

3333
constructor(actionId: string, actionLabel: string,
34-
@IQuickOpenService private readonly _quickOpenService: IQuickOpenService,
34+
@IQuickOpenService quickOpenService: IQuickOpenService,
3535
@IEditorService private readonly editorService: IEditorService
3636
) {
37-
super(actionId, actionLabel, GOTO_LINE_PREFIX, _quickOpenService);
37+
super(actionId, actionLabel, GOTO_LINE_PREFIX, quickOpenService);
3838
}
3939

40-
run(): Promise<void> {
41-
40+
async run(): Promise<void> {
4241
let activeTextEditorControl = this.editorService.activeTextEditorControl;
43-
if (!activeTextEditorControl) {
44-
return Promise.resolve();
45-
}
46-
4742
if (isDiffEditor(activeTextEditorControl)) {
4843
activeTextEditorControl = activeTextEditorControl.getModifiedEditor();
4944
}
45+
5046
let restoreOptions: IEditorOptions | null = null;
5147

5248
if (isCodeEditor(activeTextEditorControl)) {
@@ -65,7 +61,7 @@ export class GotoLineAction extends QuickOpenAction {
6561
const result = super.run();
6662

6763
if (restoreOptions) {
68-
Event.once(this._quickOpenService.onHide)(() => {
64+
Event.once(this.quickOpenService.onHide)(() => {
6965
activeTextEditorControl!.updateOptions(restoreOptions!);
7066
});
7167
}

src/vs/workbench/contrib/search/browser/anythingQuickAccess.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,24 +53,28 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
5353
private static readonly TYPING_SEARCH_DELAY = 200; // this delay accommodates for the user typing a word and then stops typing to start searching
5454

5555
private readonly pickState = new class {
56+
5657
scorerCache: ScorerCache = Object.create(null);
5758
fileQueryCache: FileQueryCacheState | undefined = undefined;
5859

5960
lastOriginalFilter: string | undefined = undefined;
6061
lastFilter: string | undefined = undefined;
6162
lastRange: IRange | undefined = undefined;
6263

64+
isQuickNavigating: boolean | undefined = undefined;
65+
6366
constructor(private readonly provider: AnythingQuickAccessProvider) { }
6467

65-
reset(prepareForSearching: boolean): void {
68+
reset(isQuickNavigating: boolean): void {
6669

6770
// Caches
68-
if (prepareForSearching) {
71+
if (!isQuickNavigating) {
6972
this.fileQueryCache = this.provider.createFileQueryCache();
7073
this.scorerCache = Object.create(null);
7174
}
7275

7376
// Other
77+
this.isQuickNavigating = isQuickNavigating;
7478
this.lastOriginalFilter = undefined;
7579
this.lastFilter = undefined;
7680
this.lastRange = undefined;
@@ -113,7 +117,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
113117
provide(picker: IQuickPick<IAnythingQuickPickItem>, token: CancellationToken): IDisposable {
114118

115119
// Reset the pick state for this run
116-
this.pickState.reset(!picker.quickNavigate);
120+
this.pickState.reset(!!picker.quickNavigate);
117121

118122
// Start picker
119123
return super.provide(picker, token);
@@ -154,11 +158,13 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
154158
return {
155159

156160
// Fast picks: editor history
157-
picks: historyEditorPicks.length > 0 ?
158-
[
159-
{ type: 'separator', label: localize('recentlyOpenedSeparator', "recently opened") },
160-
...historyEditorPicks
161-
] : [],
161+
picks:
162+
(this.pickState.isQuickNavigating || historyEditorPicks.length === 0) ?
163+
historyEditorPicks :
164+
[
165+
{ type: 'separator', label: localize('recentlyOpenedSeparator', "recently opened") },
166+
...historyEditorPicks
167+
],
162168

163169
// Slow picks: files and symbols
164170
additionalPicks: (async (): Promise<Array<IAnythingQuickPickItem | IQuickPickSeparator>> => {
@@ -499,6 +505,10 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
499505
description,
500506
iconClasses: getIconClasses(this.modelService, this.modeService, resource),
501507
buttons: (() => {
508+
if (this.pickState.isQuickNavigating) {
509+
return undefined; // no actions when quick navigating
510+
}
511+
502512
const openSideBySideDirection = configuration.openSideBySideDirection;
503513
const buttons: IQuickInputButton[] = [];
504514

0 commit comments

Comments
 (0)