Skip to content

Commit 6cba561

Browse files
committed
Writeable active and selected items (#49340, fixes vscode-azure-account#67)
1 parent 05b5db7 commit 6cba561

File tree

9 files changed

+214
-58
lines changed

9 files changed

+214
-58
lines changed

extensions/vscode-api-tests/src/singlefolder-tests/quickInput.test.ts

+79-44
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ import * as assert from 'assert';
99
import { window, commands } from 'vscode';
1010
import { closeAllEditors } from '../utils';
1111

12+
interface QuickPickExpected {
13+
events: string[];
14+
activeItems: string[][];
15+
selectionItems: string[][];
16+
acceptedItems: string[][];
17+
}
18+
1219
suite('window namespace tests', function () {
1320

1421
suite('QuickInput tests', function () {
@@ -20,59 +27,87 @@ suite('window namespace tests', function () {
2027
_done(err);
2128
};
2229

23-
const expectedEvents = ['active', 'active', 'selection', 'accept', 'hide'];
24-
const expectedActiveItems = [['eins'], ['zwei']];
25-
const expectedSelectionItems = [['zwei']];
30+
const quickPick = createQuickPick({
31+
events: ['active', 'active', 'selection', 'accept', 'hide'],
32+
activeItems: [['eins'], ['zwei']],
33+
selectionItems: [['zwei']],
34+
acceptedItems: [['zwei']],
35+
}, done);
36+
quickPick.items = ['eins', 'zwei', 'drei'].map(label => ({ label }));
37+
quickPick.show();
2638

27-
const quickPick = window.createQuickPick();
28-
quickPick.onDidChangeActive(items => {
29-
try {
30-
assert.equal('active', expectedEvents.shift());
31-
const expected = expectedActiveItems.shift();
32-
assert.deepEqual(items.map(item => item.label), expected);
33-
assert.deepEqual(quickPick.activeItems.map(item => item.label), expected);
34-
} catch (err) {
35-
done(err);
36-
}
37-
});
38-
quickPick.onDidChangeSelection(items => {
39-
try {
40-
assert.equal('selection', expectedEvents.shift());
41-
const expected = expectedSelectionItems.shift();
42-
assert.deepEqual(items.map(item => item.label), expected);
43-
assert.deepEqual(quickPick.selectedItems.map(item => item.label), expected);
44-
} catch (err) {
45-
done(err);
46-
}
47-
});
48-
quickPick.onDidAccept(() => {
49-
try {
50-
assert.equal('accept', expectedEvents.shift());
51-
const expected = ['zwei'];
52-
assert.deepEqual(quickPick.activeItems.map(item => item.label), expected);
53-
assert.deepEqual(quickPick.selectedItems.map(item => item.label), expected);
54-
quickPick.dispose();
55-
} catch (err) {
56-
done(err);
57-
}
58-
});
59-
quickPick.onDidHide(() => {
60-
try {
61-
assert.equal('hide', expectedEvents.shift());
62-
done();
63-
} catch (err) {
64-
done(err);
65-
}
66-
});
39+
(async () => {
40+
await commands.executeCommand('workbench.action.quickOpenSelectNext');
41+
await commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem');
42+
})()
43+
.catch(err => done(err));
44+
});
6745

46+
test('createQuickPick, focus second', function (_done) {
47+
let done = (err?: any) => {
48+
done = () => {};
49+
_done(err);
50+
};
51+
52+
const quickPick = createQuickPick({
53+
events: ['active', 'selection', 'accept', 'hide'],
54+
activeItems: [['zwei']],
55+
selectionItems: [['zwei']],
56+
acceptedItems: [['zwei']],
57+
}, done);
6858
quickPick.items = ['eins', 'zwei', 'drei'].map(label => ({ label }));
59+
quickPick.activeItems = [quickPick.items[1]];
6960
quickPick.show();
7061

7162
(async () => {
72-
await commands.executeCommand('workbench.action.quickOpenSelectNext');
7363
await commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem');
7464
})()
7565
.catch(err => done(err));
7666
});
7767
});
7868
});
69+
70+
function createQuickPick(expected: QuickPickExpected, done: (err?: any) => void) {
71+
const quickPick = window.createQuickPick();
72+
quickPick.onDidChangeActive(items => {
73+
try {
74+
assert.equal('active', expected.events.shift());
75+
const expectedItems = expected.activeItems.shift();
76+
assert.deepEqual(items.map(item => item.label), expectedItems);
77+
assert.deepEqual(quickPick.activeItems.map(item => item.label), expectedItems);
78+
} catch (err) {
79+
done(err);
80+
}
81+
});
82+
quickPick.onDidChangeSelection(items => {
83+
try {
84+
assert.equal('selection', expected.events.shift());
85+
const expectedItems = expected.selectionItems.shift();
86+
assert.deepEqual(items.map(item => item.label), expectedItems);
87+
assert.deepEqual(quickPick.selectedItems.map(item => item.label), expectedItems);
88+
} catch (err) {
89+
done(err);
90+
}
91+
});
92+
quickPick.onDidAccept(() => {
93+
try {
94+
assert.equal('accept', expected.events.shift());
95+
const expectedItems = expected.acceptedItems.shift();
96+
assert.deepEqual(quickPick.activeItems.map(item => item.label), expectedItems);
97+
assert.deepEqual(quickPick.selectedItems.map(item => item.label), expectedItems);
98+
quickPick.dispose();
99+
} catch (err) {
100+
done(err);
101+
}
102+
});
103+
quickPick.onDidHide(() => {
104+
try {
105+
assert.equal('hide', expected.events.shift());
106+
done();
107+
} catch (err) {
108+
done(err);
109+
}
110+
});
111+
112+
return quickPick;
113+
}

extensions/vscode-api-tests/src/singlefolder-tests/window.test.ts

+12
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,18 @@ suite('window namespace tests', () => {
440440
assert.deepStrictEqual(await picks, ['eins', 'zwei']);
441441
});
442442

443+
test('showQuickPick, keep selection (Microsoft/vscode-azure-account#67)', async function () {
444+
const picks = window.showQuickPick([
445+
{ label: 'eins' },
446+
{ label: 'zwei', picked: true },
447+
{ label: 'drei', picked: true }
448+
], {
449+
canPickMany: true
450+
});
451+
await commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem');
452+
assert.deepStrictEqual((await picks)!.map(pick => pick.label), ['zwei', 'drei']);
453+
});
454+
443455
test('showQuickPick, undefined on cancel', function () {
444456
const source = new CancellationTokenSource();
445457
const p = window.showQuickPick(['eins', 'zwei', 'drei'], undefined, source.token);

src/vs/platform/quickinput/common/quickInput.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -131,11 +131,11 @@ export interface IQuickPick extends IQuickInput {
131131

132132
matchOnDetail: boolean;
133133

134-
readonly activeItems: ReadonlyArray<IQuickPickItem>;
134+
activeItems: ReadonlyArray<IQuickPickItem>;
135135

136136
readonly onDidChangeActive: Event<IQuickPickItem[]>;
137137

138-
readonly selectedItems: ReadonlyArray<IQuickPickItem>;
138+
selectedItems: ReadonlyArray<IQuickPickItem>;
139139

140140
readonly onDidChangeSelection: Event<IQuickPickItem[]>;
141141
}

src/vs/vscode.proposed.d.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -581,11 +581,11 @@ declare module 'vscode' {
581581

582582
matchOnDetail: boolean;
583583

584-
readonly activeItems: ReadonlyArray<QuickPickItem>;
584+
activeItems: ReadonlyArray<QuickPickItem>;
585585

586586
readonly onDidChangeActive: Event<QuickPickItem[]>;
587587

588-
readonly selectedItems: ReadonlyArray<QuickPickItem>;
588+
selectedItems: ReadonlyArray<QuickPickItem>;
589589

590590
readonly onDidChangeSelection: Event<QuickPickItem[]>;
591591
}

src/vs/workbench/api/electron-browser/mainThreadQuickOpen.ts

+30-8
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ import { ExtHostContext, MainThreadQuickOpenShape, ExtHostQuickOpenShape, Transf
1212
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
1313
import URI from 'vs/base/common/uri';
1414

15+
interface QuickInputSession {
16+
input: IQuickInput;
17+
handlesToItems: Map<number, TransferQuickPickItems>;
18+
}
19+
1520
@extHostNamedCustomer(MainContext.MainThreadQuickOpen)
1621
export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
1722

@@ -114,7 +119,7 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
114119

115120
// ---- QuickInput
116121

117-
private sessions = new Map<number, IQuickInput>();
122+
private sessions = new Map<number, QuickInputSession>();
118123

119124
$createOrUpdate(params: TransferQuickInput): TPromise<void> {
120125
const sessionId = params.id;
@@ -140,7 +145,10 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
140145
input.onDidHide(() => {
141146
this._proxy.$onDidHide(sessionId);
142147
});
143-
session = input;
148+
session = {
149+
input,
150+
handlesToItems: new Map()
151+
};
144152
} else {
145153
const input = this._quickInputService.createInputBox();
146154
input.onDidAccept(() => {
@@ -155,22 +163,36 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
155163
input.onDidHide(() => {
156164
this._proxy.$onDidHide(sessionId);
157165
});
158-
session = input;
166+
session = {
167+
input,
168+
handlesToItems: new Map()
169+
};
159170
}
160171
this.sessions.set(sessionId, session);
161172
}
173+
const { input, handlesToItems } = session;
162174
for (const param in params) {
163175
if (param === 'id' || param === 'type') {
164176
continue;
165177
}
166178
if (param === 'visible') {
167179
if (params.visible) {
168-
session.show();
180+
input.show();
169181
} else {
170-
session.hide();
182+
input.hide();
171183
}
184+
} else if (param === 'items') {
185+
handlesToItems.clear();
186+
params[param].forEach(item => {
187+
handlesToItems.set(item.handle, item);
188+
});
189+
input[param] = params[param];
190+
} else if (param === 'activeItems' || param === 'selectedItems') {
191+
input[param] = params[param]
192+
.filter(handle => handlesToItems.has(handle))
193+
.map(handle => handlesToItems.get(handle));
172194
} else if (param === 'buttons') {
173-
session[param] = params.buttons.map(button => {
195+
input[param] = params.buttons.map(button => {
174196
if (button.handle === -1) {
175197
return this._quickInputService.backButton;
176198
}
@@ -185,7 +207,7 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
185207
};
186208
});
187209
} else {
188-
session[param] = params[param];
210+
input[param] = params[param];
189211
}
190212
}
191213
return TPromise.as(undefined);
@@ -194,7 +216,7 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
194216
$dispose(sessionId: number): TPromise<void> {
195217
const session = this.sessions.get(sessionId);
196218
if (session) {
197-
session.dispose();
219+
session.input.dispose();
198220
this.sessions.delete(sessionId);
199221
}
200222
return TPromise.as(undefined);

src/vs/workbench/api/node/extHost.protocol.ts

+4
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,10 @@ export interface TransferQuickPick extends BaseTransferQuickInput {
380380

381381
items?: TransferQuickPickItems[];
382382

383+
activeItems?: number[];
384+
385+
selectedItems?: number[];
386+
383387
canSelectMany?: boolean;
384388

385389
ignoreFocusOut?: boolean;

src/vs/workbench/api/node/extHostQuickOpen.ts

+13
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,7 @@ class ExtHostQuickPick extends ExtHostQuickInput implements QuickPick {
455455

456456
private _items: QuickPickItem[] = [];
457457
private _handlesToItems = new Map<number, QuickPickItem>();
458+
private _itemsToHandles = new Map<QuickPickItem, number>();
458459
private _canSelectMany = false;
459460
private _matchOnDescription = true;
460461
private _matchOnDetail = true;
@@ -479,8 +480,10 @@ class ExtHostQuickPick extends ExtHostQuickInput implements QuickPick {
479480
set items(items: QuickPickItem[]) {
480481
this._items = items;
481482
this._handlesToItems.clear();
483+
this._itemsToHandles.clear();
482484
items.forEach((item, i) => {
483485
this._handlesToItems.set(i, item);
486+
this._itemsToHandles.set(item, i);
484487
});
485488
this.update({
486489
items: items.map((item, i) => ({
@@ -524,12 +527,22 @@ class ExtHostQuickPick extends ExtHostQuickInput implements QuickPick {
524527
return this._activeItems;
525528
}
526529

530+
set activeItems(activeItems: QuickPickItem[]) {
531+
this._activeItems = activeItems.filter(item => this._itemsToHandles.has(item));
532+
this.update({ activeItems: this._activeItems.map(item => this._itemsToHandles.get(item)) });
533+
}
534+
527535
onDidChangeActive = this._onDidChangeActiveEmitter.event;
528536

529537
get selectedItems() {
530538
return this._selectedItems;
531539
}
532540

541+
set selectedItems(selectedItems: QuickPickItem[]) {
542+
this._selectedItems = selectedItems.filter(item => this._itemsToHandles.has(item));
543+
this.update({ selectedItems: this._selectedItems.map(item => this._itemsToHandles.get(item)) });
544+
}
545+
533546
onDidChangeSelection = this._onDidChangeSelectionEmitter.event;
534547

535548
_fireDidChangeActive(handles: number[]) {

0 commit comments

Comments
 (0)