Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ src/test/interpreters/display/interpreterSelectionTip.unit.test.ts
src/test/interpreters/display.unit.test.ts

src/test/configuration/interpreterSelector/interpreterSelector.unit.test.ts
src/test/configuration/interpreterSelector/commands/setInterpreter.unit.test.ts

src/test/install/channelManager.channels.test.ts
src/test/install/channelManager.messages.test.ts
Expand Down Expand Up @@ -322,7 +321,6 @@ src/test/workspaceSymbols/generator.unit.test.ts
src/client/interpreter/interpreterService.ts
src/client/interpreter/configuration/interpreterComparer.ts
src/client/interpreter/configuration/interpreterSelector/commands/base.ts
src/client/interpreter/configuration/interpreterSelector/commands/setInterpreter.ts
src/client/interpreter/configuration/interpreterSelector/commands/resetInterpreter.ts
src/client/interpreter/configuration/interpreterSelector/commands/setShebangInterpreter.ts
src/client/interpreter/configuration/interpreterSelector/interpreterSelector.ts
Expand Down Expand Up @@ -570,7 +568,6 @@ src/client/common/utils/enum.ts
src/client/common/utils/async.ts
src/client/common/utils/localize.ts
src/client/common/utils/platform.ts
src/client/common/utils/multiStepInput.ts
src/client/common/utils/stopWatch.ts
src/client/common/utils/random.ts
src/client/common/utils/serializers.ts
Expand Down
53 changes: 25 additions & 28 deletions src/client/common/utils/multiStepInput.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

/* eslint-disable max-classes-per-file */

'use strict';

import { inject, injectable } from 'inversify';
Expand All @@ -12,11 +14,17 @@ import { IApplicationShell } from '../application/types';

export class InputFlowAction {
public static back = new InputFlowAction();

public static cancel = new InputFlowAction();

public static resume = new InputFlowAction();
private constructor() {}

private constructor() {
/** No body. */
}
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type InputStep<T extends any> = (input: MultiStepInput<T>, state: T) => Promise<InputStep<T> | void>;

export interface IQuickPickParameters<T extends QuickPickItem> {
Expand All @@ -31,7 +39,6 @@ export interface IQuickPickParameters<T extends QuickPickItem> {
matchOnDescription?: boolean;
matchOnDetail?: boolean;
acceptFilterBoxTextAsSelection?: boolean;
shouldResume?(): Promise<boolean>;
}

export interface InputBoxParameters {
Expand All @@ -43,11 +50,10 @@ export interface InputBoxParameters {
prompt: string;
buttons?: QuickInputButton[];
validate(value: string): Promise<string | undefined>;
shouldResume?(): Promise<boolean>;
}

type MultiStepInputQuickPicResponseType<T, P> = T | (P extends { buttons: (infer I)[] } ? I : never);
type MultiStepInputInputBoxResponseType<P> = string | (P extends { buttons: (infer I)[] } ? I : never);
type MultiStepInputQuickPicResponseType<T, P> = T | (P extends { buttons: (infer I)[] } ? I : never) | undefined;
type MultiStepInputInputBoxResponseType<P> = string | (P extends { buttons: (infer I)[] } ? I : never) | undefined;
export interface IMultiStepInput<S> {
run(start: InputStep<S>, state: S): Promise<void>;
showQuickPick<T extends QuickPickItem, P extends IQuickPickParameters<T>>({
Expand All @@ -58,7 +64,6 @@ export interface IMultiStepInput<S> {
activeItem,
placeholder,
buttons,
shouldResume,
}: P): Promise<MultiStepInputQuickPicResponseType<T, P>>;
showInputBox<P extends InputBoxParameters>({
title,
Expand All @@ -68,15 +73,17 @@ export interface IMultiStepInput<S> {
prompt,
validate,
buttons,
shouldResume,
}: P): Promise<MultiStepInputInputBoxResponseType<P>>;
}

export class MultiStepInput<S> implements IMultiStepInput<S> {
private current?: QuickInput;

private steps: InputStep<S>[] = [];

constructor(private readonly shell: IApplicationShell) {}
public run(start: InputStep<S>, state: S) {

public run(start: InputStep<S>, state: S): Promise<void> {
return this.stepThrough(start, state);
}

Expand All @@ -88,7 +95,6 @@ export class MultiStepInput<S> implements IMultiStepInput<S> {
activeItem,
placeholder,
buttons,
shouldResume,
matchOnDescription,
matchOnDetail,
acceptFilterBoxTextAsSelection,
Expand Down Expand Up @@ -116,24 +122,20 @@ export class MultiStepInput<S> implements IMultiStepInput<S> {
if (item === QuickInputButtons.Back) {
reject(InputFlowAction.back);
} else {
resolve(<any>item);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
resolve(item as any);
}
}),
input.onDidChangeSelection((selectedItems) => resolve(selectedItems[0])),
input.onDidHide(() => {
(async () => {
reject(
shouldResume && (await shouldResume())
? InputFlowAction.resume
: InputFlowAction.cancel,
);
})().catch(reject);
resolve(undefined);
}),
);
if (acceptFilterBoxTextAsSelection) {
disposables.push(
input.onDidAccept(() => {
resolve(<any>input.value);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
resolve(input.value as any);
}),
);
}
Expand All @@ -157,7 +159,6 @@ export class MultiStepInput<S> implements IMultiStepInput<S> {
validate,
password,
buttons,
shouldResume,
}: P): Promise<MultiStepInputInputBoxResponseType<P>> {
const disposables: Disposable[] = [];
try {
Expand All @@ -166,7 +167,7 @@ export class MultiStepInput<S> implements IMultiStepInput<S> {
input.title = title;
input.step = step;
input.totalSteps = totalSteps;
input.password = password ? true : false;
input.password = !!password;
input.value = value || '';
input.prompt = prompt;
input.ignoreFocusOut = true;
Expand All @@ -177,7 +178,8 @@ export class MultiStepInput<S> implements IMultiStepInput<S> {
if (item === QuickInputButtons.Back) {
reject(InputFlowAction.back);
} else {
resolve(<any>item);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
resolve(item as any);
}
}),
input.onDidAccept(async () => {
Expand All @@ -199,13 +201,7 @@ export class MultiStepInput<S> implements IMultiStepInput<S> {
}
}),
input.onDidHide(() => {
(async () => {
reject(
shouldResume && (await shouldResume())
? InputFlowAction.resume
: InputFlowAction.cancel,
);
})().catch(reject);
resolve(undefined);
}),
);
if (this.current) {
Expand Down Expand Up @@ -254,6 +250,7 @@ export interface IMultiStepInputFactory {
@injectable()
export class MultiStepInputFactory {
constructor(@inject(IApplicationShell) private readonly shell: IApplicationShell) {}

public create<S>(): IMultiStepInput<S> {
return new MultiStepInput<S>(this.shell);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export class SetInterpreterCommand extends BaseInterpreterSelectorCommand {
super(pythonPathUpdaterService, commandManager, applicationShell, workspaceService);
}

public async activate() {
public async activate(): Promise<void> {
this.disposables.push(
this.commandManager.registerCommand(Commands.Set_Interpreter, this.setInterpreter.bind(this)),
);
Expand Down Expand Up @@ -74,12 +74,15 @@ export class SetInterpreterCommand extends BaseInterpreterSelectorCommand {
});

if (selection === undefined) {
return;
sendTelemetryEvent(EventName.SELECT_INTERPRETER_SELECTED, undefined, { action: 'escape' });
} else if (selection.label === enterInterpreterPathSuggestion.label) {
return this._enterOrBrowseInterpreterPath(input, state);
} else {
sendTelemetryEvent(EventName.SELECT_INTERPRETER_SELECTED, undefined, { action: 'selected' });
state.path = (selection as IInterpreterQuickPickItem).path;
}

return undefined;
}

@captureTelemetry(EventName.SELECT_INTERPRETER_ENTER_BUTTON)
Expand Down Expand Up @@ -122,16 +125,18 @@ export class SetInterpreterCommand extends BaseInterpreterSelectorCommand {
}

@captureTelemetry(EventName.SELECT_INTERPRETER)
public async setInterpreter() {
public async setInterpreter(): Promise<void> {
const targetConfig = await this.getConfigTarget();
if (!targetConfig) {
return;
}
const configTarget = targetConfig.configTarget;

const { configTarget } = targetConfig;
const wkspace = targetConfig.folderUri;
const interpreterState: InterpreterStateArgs = { path: undefined, workspace: wkspace };
const multiStep = this.multiStepFactory.create<InterpreterStateArgs>();
await multiStep.run((input, s) => this._pickInterpreter(input, s), interpreterState);

if (interpreterState.path !== undefined) {
// User may choose to have an empty string stored, so variable `interpreterState.path` may be
// an empty string, in which case we should update.
Expand Down
1 change: 1 addition & 0 deletions src/client/telemetry/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export enum EventName {
SELECT_INTERPRETER = 'SELECT_INTERPRETER',
SELECT_INTERPRETER_ENTER_BUTTON = 'SELECT_INTERPRETER_ENTER_BUTTON',
SELECT_INTERPRETER_ENTER_CHOICE = 'SELECT_INTERPRETER_ENTER_CHOICE',
SELECT_INTERPRETER_SELECTED = 'SELECT_INTERPRETER_SELECTED',
PYTHON_INTERPRETER = 'PYTHON_INTERPRETER',
PYTHON_INSTALL_PACKAGE = 'PYTHON_INSTALL_PACKAGE',
PYTHON_INTERPRETER_DISCOVERY = 'PYTHON_INTERPRETER_DISCOVERY',
Expand Down
11 changes: 11 additions & 0 deletions src/client/telemetry/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,17 @@ export interface IEventNamePropertyMapping {
*/
choice: 'enter' | 'browse';
};
/**
* Telemetry event sent after an action has been taken while the interpreter quickpick was displayed,
* and if the action was not 'Enter interpreter path'.
*/
[EventName.SELECT_INTERPRETER_SELECTED]: {
/**
* 'escape' if the quickpick was dismissed.
* 'selected' if an interpreter was selected.
*/
action: 'escape' | 'selected';
};
/**
* Telemetry event sent with details after updating the python interpreter
*/
Expand Down
Loading