Skip to content

Commit

Permalink
Writeable active and selected items (#49340, fixes vscode-azure-accou…
Browse files Browse the repository at this point in the history
…nt#67)
  • Loading branch information
chrmarti committed Jun 20, 2018
1 parent 05b5db7 commit 6cba561
Show file tree
Hide file tree
Showing 9 changed files with 214 additions and 58 deletions.
123 changes: 79 additions & 44 deletions extensions/vscode-api-tests/src/singlefolder-tests/quickInput.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ import * as assert from 'assert';
import { window, commands } from 'vscode';
import { closeAllEditors } from '../utils';

interface QuickPickExpected {
events: string[];
activeItems: string[][];
selectionItems: string[][];
acceptedItems: string[][];
}

suite('window namespace tests', function () {

suite('QuickInput tests', function () {
Expand All @@ -20,59 +27,87 @@ suite('window namespace tests', function () {
_done(err);
};

const expectedEvents = ['active', 'active', 'selection', 'accept', 'hide'];
const expectedActiveItems = [['eins'], ['zwei']];
const expectedSelectionItems = [['zwei']];
const quickPick = createQuickPick({
events: ['active', 'active', 'selection', 'accept', 'hide'],
activeItems: [['eins'], ['zwei']],
selectionItems: [['zwei']],
acceptedItems: [['zwei']],
}, done);
quickPick.items = ['eins', 'zwei', 'drei'].map(label => ({ label }));
quickPick.show();

const quickPick = window.createQuickPick();
quickPick.onDidChangeActive(items => {
try {
assert.equal('active', expectedEvents.shift());
const expected = expectedActiveItems.shift();
assert.deepEqual(items.map(item => item.label), expected);
assert.deepEqual(quickPick.activeItems.map(item => item.label), expected);
} catch (err) {
done(err);
}
});
quickPick.onDidChangeSelection(items => {
try {
assert.equal('selection', expectedEvents.shift());
const expected = expectedSelectionItems.shift();
assert.deepEqual(items.map(item => item.label), expected);
assert.deepEqual(quickPick.selectedItems.map(item => item.label), expected);
} catch (err) {
done(err);
}
});
quickPick.onDidAccept(() => {
try {
assert.equal('accept', expectedEvents.shift());
const expected = ['zwei'];
assert.deepEqual(quickPick.activeItems.map(item => item.label), expected);
assert.deepEqual(quickPick.selectedItems.map(item => item.label), expected);
quickPick.dispose();
} catch (err) {
done(err);
}
});
quickPick.onDidHide(() => {
try {
assert.equal('hide', expectedEvents.shift());
done();
} catch (err) {
done(err);
}
});
(async () => {
await commands.executeCommand('workbench.action.quickOpenSelectNext');
await commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem');
})()
.catch(err => done(err));
});

test('createQuickPick, focus second', function (_done) {
let done = (err?: any) => {
done = () => {};
_done(err);
};

const quickPick = createQuickPick({
events: ['active', 'selection', 'accept', 'hide'],
activeItems: [['zwei']],
selectionItems: [['zwei']],
acceptedItems: [['zwei']],
}, done);
quickPick.items = ['eins', 'zwei', 'drei'].map(label => ({ label }));
quickPick.activeItems = [quickPick.items[1]];
quickPick.show();

(async () => {
await commands.executeCommand('workbench.action.quickOpenSelectNext');
await commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem');
})()
.catch(err => done(err));
});
});
});

function createQuickPick(expected: QuickPickExpected, done: (err?: any) => void) {
const quickPick = window.createQuickPick();
quickPick.onDidChangeActive(items => {
try {
assert.equal('active', expected.events.shift());
const expectedItems = expected.activeItems.shift();
assert.deepEqual(items.map(item => item.label), expectedItems);
assert.deepEqual(quickPick.activeItems.map(item => item.label), expectedItems);
} catch (err) {
done(err);
}
});
quickPick.onDidChangeSelection(items => {
try {
assert.equal('selection', expected.events.shift());
const expectedItems = expected.selectionItems.shift();
assert.deepEqual(items.map(item => item.label), expectedItems);
assert.deepEqual(quickPick.selectedItems.map(item => item.label), expectedItems);
} catch (err) {
done(err);
}
});
quickPick.onDidAccept(() => {
try {
assert.equal('accept', expected.events.shift());
const expectedItems = expected.acceptedItems.shift();
assert.deepEqual(quickPick.activeItems.map(item => item.label), expectedItems);
assert.deepEqual(quickPick.selectedItems.map(item => item.label), expectedItems);
quickPick.dispose();
} catch (err) {
done(err);
}
});
quickPick.onDidHide(() => {
try {
assert.equal('hide', expected.events.shift());
done();
} catch (err) {
done(err);
}
});

return quickPick;
}
12 changes: 12 additions & 0 deletions extensions/vscode-api-tests/src/singlefolder-tests/window.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,18 @@ suite('window namespace tests', () => {
assert.deepStrictEqual(await picks, ['eins', 'zwei']);
});

test('showQuickPick, keep selection (Microsoft/vscode-azure-account#67)', async function () {
const picks = window.showQuickPick([
{ label: 'eins' },
{ label: 'zwei', picked: true },
{ label: 'drei', picked: true }
], {
canPickMany: true
});
await commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem');
assert.deepStrictEqual((await picks)!.map(pick => pick.label), ['zwei', 'drei']);
});

test('showQuickPick, undefined on cancel', function () {
const source = new CancellationTokenSource();
const p = window.showQuickPick(['eins', 'zwei', 'drei'], undefined, source.token);
Expand Down
4 changes: 2 additions & 2 deletions src/vs/platform/quickinput/common/quickInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,11 @@ export interface IQuickPick extends IQuickInput {

matchOnDetail: boolean;

readonly activeItems: ReadonlyArray<IQuickPickItem>;
activeItems: ReadonlyArray<IQuickPickItem>;

readonly onDidChangeActive: Event<IQuickPickItem[]>;

readonly selectedItems: ReadonlyArray<IQuickPickItem>;
selectedItems: ReadonlyArray<IQuickPickItem>;

readonly onDidChangeSelection: Event<IQuickPickItem[]>;
}
Expand Down
4 changes: 2 additions & 2 deletions src/vs/vscode.proposed.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -581,11 +581,11 @@ declare module 'vscode' {

matchOnDetail: boolean;

readonly activeItems: ReadonlyArray<QuickPickItem>;
activeItems: ReadonlyArray<QuickPickItem>;

readonly onDidChangeActive: Event<QuickPickItem[]>;

readonly selectedItems: ReadonlyArray<QuickPickItem>;
selectedItems: ReadonlyArray<QuickPickItem>;

readonly onDidChangeSelection: Event<QuickPickItem[]>;
}
Expand Down
38 changes: 30 additions & 8 deletions src/vs/workbench/api/electron-browser/mainThreadQuickOpen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ import { ExtHostContext, MainThreadQuickOpenShape, ExtHostQuickOpenShape, Transf
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import URI from 'vs/base/common/uri';

interface QuickInputSession {
input: IQuickInput;
handlesToItems: Map<number, TransferQuickPickItems>;
}

@extHostNamedCustomer(MainContext.MainThreadQuickOpen)
export class MainThreadQuickOpen implements MainThreadQuickOpenShape {

Expand Down Expand Up @@ -114,7 +119,7 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {

// ---- QuickInput

private sessions = new Map<number, IQuickInput>();
private sessions = new Map<number, QuickInputSession>();

$createOrUpdate(params: TransferQuickInput): TPromise<void> {
const sessionId = params.id;
Expand All @@ -140,7 +145,10 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
input.onDidHide(() => {
this._proxy.$onDidHide(sessionId);
});
session = input;
session = {
input,
handlesToItems: new Map()
};
} else {
const input = this._quickInputService.createInputBox();
input.onDidAccept(() => {
Expand All @@ -155,22 +163,36 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
input.onDidHide(() => {
this._proxy.$onDidHide(sessionId);
});
session = input;
session = {
input,
handlesToItems: new Map()
};
}
this.sessions.set(sessionId, session);
}
const { input, handlesToItems } = session;
for (const param in params) {
if (param === 'id' || param === 'type') {
continue;
}
if (param === 'visible') {
if (params.visible) {
session.show();
input.show();
} else {
session.hide();
input.hide();
}
} else if (param === 'items') {
handlesToItems.clear();
params[param].forEach(item => {
handlesToItems.set(item.handle, item);
});
input[param] = params[param];
} else if (param === 'activeItems' || param === 'selectedItems') {
input[param] = params[param]
.filter(handle => handlesToItems.has(handle))
.map(handle => handlesToItems.get(handle));
} else if (param === 'buttons') {
session[param] = params.buttons.map(button => {
input[param] = params.buttons.map(button => {
if (button.handle === -1) {
return this._quickInputService.backButton;
}
Expand All @@ -185,7 +207,7 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
};
});
} else {
session[param] = params[param];
input[param] = params[param];
}
}
return TPromise.as(undefined);
Expand All @@ -194,7 +216,7 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
$dispose(sessionId: number): TPromise<void> {
const session = this.sessions.get(sessionId);
if (session) {
session.dispose();
session.input.dispose();
this.sessions.delete(sessionId);
}
return TPromise.as(undefined);
Expand Down
4 changes: 4 additions & 0 deletions src/vs/workbench/api/node/extHost.protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,10 @@ export interface TransferQuickPick extends BaseTransferQuickInput {

items?: TransferQuickPickItems[];

activeItems?: number[];

selectedItems?: number[];

canSelectMany?: boolean;

ignoreFocusOut?: boolean;
Expand Down
13 changes: 13 additions & 0 deletions src/vs/workbench/api/node/extHostQuickOpen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,7 @@ class ExtHostQuickPick extends ExtHostQuickInput implements QuickPick {

private _items: QuickPickItem[] = [];
private _handlesToItems = new Map<number, QuickPickItem>();
private _itemsToHandles = new Map<QuickPickItem, number>();
private _canSelectMany = false;
private _matchOnDescription = true;
private _matchOnDetail = true;
Expand All @@ -479,8 +480,10 @@ class ExtHostQuickPick extends ExtHostQuickInput implements QuickPick {
set items(items: QuickPickItem[]) {
this._items = items;
this._handlesToItems.clear();
this._itemsToHandles.clear();
items.forEach((item, i) => {
this._handlesToItems.set(i, item);
this._itemsToHandles.set(item, i);
});
this.update({
items: items.map((item, i) => ({
Expand Down Expand Up @@ -524,12 +527,22 @@ class ExtHostQuickPick extends ExtHostQuickInput implements QuickPick {
return this._activeItems;
}

set activeItems(activeItems: QuickPickItem[]) {
this._activeItems = activeItems.filter(item => this._itemsToHandles.has(item));
this.update({ activeItems: this._activeItems.map(item => this._itemsToHandles.get(item)) });
}

onDidChangeActive = this._onDidChangeActiveEmitter.event;

get selectedItems() {
return this._selectedItems;
}

set selectedItems(selectedItems: QuickPickItem[]) {
this._selectedItems = selectedItems.filter(item => this._itemsToHandles.has(item));
this.update({ selectedItems: this._selectedItems.map(item => this._itemsToHandles.get(item)) });
}

onDidChangeSelection = this._onDidChangeSelectionEmitter.event;

_fireDidChangeActive(handles: number[]) {
Expand Down

0 comments on commit 6cba561

Please sign in to comment.