Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TS: Add setting to prompt users about workspace tsdk #95566

Merged
merged 2 commits into from Apr 22, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions extensions/typescript-language-features/package.json
Expand Up @@ -140,6 +140,12 @@
"usesOnlineServices"
]
},
"typescript.enablePromptUseWorkspaceTsdk": {
"type": "boolean",
"default": false,
"description": "%typescript.enablePromptUseWorkspaceTsdk%",
"scope": "window"
},
"typescript.npm": {
"type": [
"string",
Expand Down
1 change: 1 addition & 0 deletions extensions/typescript-language-features/package.nls.json
Expand Up @@ -7,6 +7,7 @@
"configuration.suggest.includeAutomaticOptionalChainCompletions": "Enable/disable showing completions on potentially undefined values that insert an optional chain call. Requires TS 3.7+ and strict null checks to be enabled.",
"typescript.tsdk.desc": "Specifies the folder path to the tsserver and lib*.d.ts files under a TypeScript install to use for IntelliSense, for example: `./node_modules/typescript/lib`.\n\n- When specified as a user setting, the TypeScript version from `typescript.tsdk` automatically replaces the built-in TypeScript version.\n- When specified as a workspace setting, `typescript.tsdk` allows you to switch to use that workspace version of TypeScript for IntelliSense with the `TypeScript: Select TypeScript version` command.\n\nSee the [TypeScript documentation](https://code.visualstudio.com/docs/typescript/typescript-compiling#_using-newer-typescript-versions) for more detail about managing TypeScript versions.",
"typescript.disableAutomaticTypeAcquisition": "Disables automatic type acquisition. Automatic type acquisition fetches `@types` packages from npm to improve IntelliSense for external libraries.",
"typescript.enablePromptUseWorkspaceTsdk": "Enables prompting of users to use the TypeScript version configured in the workspace for Intellisense.",
"typescript.tsserver.log": "Enables logging of the TS server to a file. This log can be used to diagnose TS Server issues. The log may contain file paths, source code, and other potentially sensitive information from your project.",
"typescript.tsserver.pluginPaths": "Additional paths to discover TypeScript Language Service plugins. Requires using TypeScript 2.3.0 or newer in the workspace.",
"typescript.tsserver.pluginPaths.item": "Either an absolute or relative path. Relative path will be resolved against workspace folder(s).",
Expand Down
Expand Up @@ -140,7 +140,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType
this._configuration = TypeScriptServiceConfiguration.loadFromWorkspace();
this.versionProvider = new TypeScriptVersionProvider(this._configuration);
this.pluginPathsProvider = new TypeScriptPluginPathsProvider(this._configuration);
this._versionManager = this._register(new TypeScriptVersionManager(this.versionProvider, this.workspaceState));
this._versionManager = this._register(new TypeScriptVersionManager(this._configuration, this.versionProvider, this.workspaceState));
this._register(this._versionManager.onDidPickNewVersion(() => {
this.restartTsServer();
}));
Expand All @@ -163,6 +163,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType
this._configuration = TypeScriptServiceConfiguration.loadFromWorkspace();

this.versionProvider.updateConfiguration(this._configuration);
this._versionManager.updateConfiguration(this._configuration);
this.pluginPathsProvider.updateConfiguration(this._configuration);
this.tracer.updateConfiguration();

Expand Down
Expand Up @@ -59,6 +59,7 @@ export class TypeScriptServiceConfiguration {
public readonly useSeparateSyntaxServer: boolean;
public readonly enableProjectDiagnostics: boolean;
public readonly maxTsServerMemory: number;
public readonly enablePromptUseWorkspaceTsdk: boolean;
public readonly watchOptions: protocol.WatchOptions | undefined;

public static loadFromWorkspace(): TypeScriptServiceConfiguration {
Expand All @@ -80,6 +81,7 @@ export class TypeScriptServiceConfiguration {
this.useSeparateSyntaxServer = TypeScriptServiceConfiguration.readUseSeparateSyntaxServer(configuration);
this.enableProjectDiagnostics = TypeScriptServiceConfiguration.readEnableProjectDiagnostics(configuration);
this.maxTsServerMemory = TypeScriptServiceConfiguration.readMaxTsServerMemory(configuration);
this.enablePromptUseWorkspaceTsdk = TypeScriptServiceConfiguration.readEnablePromptUseWorkspaceTsdk(configuration);
DuncanWalter marked this conversation as resolved.
Show resolved Hide resolved
this.watchOptions = TypeScriptServiceConfiguration.readWatchOptions(configuration);
}

Expand All @@ -96,7 +98,8 @@ export class TypeScriptServiceConfiguration {
&& this.useSeparateSyntaxServer === other.useSeparateSyntaxServer
&& this.enableProjectDiagnostics === other.enableProjectDiagnostics
&& this.maxTsServerMemory === other.maxTsServerMemory
&& objects.equals(this.watchOptions, other.watchOptions);
&& objects.equals(this.watchOptions, other.watchOptions)
&& this.enablePromptUseWorkspaceTsdk === other.enablePromptUseWorkspaceTsdk;
}

private static fixPathPrefixes(inspectValue: string): string {
Expand Down Expand Up @@ -175,4 +178,8 @@ export class TypeScriptServiceConfiguration {
}
return Math.max(memoryInMB, minimumMaxMemory);
}

private static readEnablePromptUseWorkspaceTsdk(configuration: vscode.WorkspaceConfiguration): boolean {
return configuration.get<boolean>('typescript.enablePromptUseWorkspaceTsdk', false);
}
}
Expand Up @@ -7,10 +7,12 @@ import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
import { TypeScriptVersion, TypeScriptVersionProvider } from './versionProvider';
import { Disposable } from './dispose';
import { TypeScriptServiceConfiguration } from '../utils/configuration';

const localize = nls.loadMessageBundle();

const useWorkspaceTsdkStorageKey = 'typescript.useWorkspaceTsdk';
const suppressPromptWorkspaceTsdkStorageKey = 'typescript.suppressPromptWorkspaceTsdk';

interface QuickPickItem extends vscode.QuickPickItem {
run(): void;
Expand All @@ -21,6 +23,7 @@ export class TypeScriptVersionManager extends Disposable {
private _currentVersion: TypeScriptVersion;

public constructor(
private configuration: TypeScriptServiceConfiguration,
private readonly versionProvider: TypeScriptVersionProvider,
private readonly workspaceState: vscode.Memento
) {
Expand All @@ -34,11 +37,30 @@ export class TypeScriptVersionManager extends Disposable {
this._currentVersion = localVersion;
}
}

if (this.isInPromptWorkspaceTsdkState(configuration)) {
setImmediate(() => {
this.promptUseWorkspaceTsdk();
});
}

}

private readonly _onDidPickNewVersion = this._register(new vscode.EventEmitter<void>());
public readonly onDidPickNewVersion = this._onDidPickNewVersion.event;

public updateConfiguration(nextConfiguration: TypeScriptServiceConfiguration) {
const lastConfiguration = this.configuration;
this.configuration = nextConfiguration;

if (
!this.isInPromptWorkspaceTsdkState(lastConfiguration)
&& this.isInPromptWorkspaceTsdkState(nextConfiguration)
) {
this.promptUseWorkspaceTsdk();
}
}

public get currentVersion(): TypeScriptVersion {
return this._currentVersion;
}
Expand Down Expand Up @@ -71,7 +93,7 @@ export class TypeScriptVersionManager extends Disposable {
detail: bundledVersion.pathLabel,
run: async () => {
await this.workspaceState.update(useWorkspaceTsdkStorageKey, false);
this.updateForPickedVersion(bundledVersion);
this.updateActiveVersion(bundledVersion);
},
};
}
Expand All @@ -88,13 +110,38 @@ export class TypeScriptVersionManager extends Disposable {
await this.workspaceState.update(useWorkspaceTsdkStorageKey, true);
const tsConfig = vscode.workspace.getConfiguration('typescript');
await tsConfig.update('tsdk', version.pathLabel, false);
this.updateForPickedVersion(version);
this.updateActiveVersion(version);
},
};
});
}

private updateForPickedVersion(pickedVersion: TypeScriptVersion) {
private async promptUseWorkspaceTsdk(): Promise<void> {
const workspaceVersion = this.versionProvider.localVersion;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please also make sure the user is not prompted if typescript is installed locally but typescript.tsdk is not set

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It follows the desired behavior in local testing. The check to see whether the prompt should runs is checking for the tsdk setting in configuration here. The intent is that promptUseWorkspaceTsdk should never be called in situations where the user shouldn't be prompted. Confusingly, promptUseWorkspaceTsdk reads the local version from the versionProvider to get a reference to the instance of TypeScriptVersion. configuation.localTsdk is a string, which isn't enough to set the new TS version AFAIK


if (workspaceVersion === undefined) {
throw new Error('Could not prompt to use workspace TypeScript version because no workspace version is specified');
}

const allowIt = localize('allow', 'Allow');
const dismissPrompt = localize('dismiss', 'Dismiss');
const suppressPrompt = localize('suppress prompt', 'Never in this Workspace');

const result = await vscode.window.showInformationMessage(localize('promptUseWorkspaceTsdk', 'This workspace contains a TypeScript version. Would you like to use the workspace TypeScript version for TypeScript and JavaScript language features?'),
allowIt,
dismissPrompt,
suppressPrompt
);

if (result === allowIt) {
await this.workspaceState.update(useWorkspaceTsdkStorageKey, true);
this.updateActiveVersion(workspaceVersion);
} else if (result === suppressPrompt) {
await this.workspaceState.update(suppressPromptWorkspaceTsdkStorageKey, true);
}
}

private updateActiveVersion(pickedVersion: TypeScriptVersion) {
const oldVersion = this.currentVersion;
this._currentVersion = pickedVersion;
if (!oldVersion.eq(pickedVersion)) {
Expand All @@ -105,6 +152,19 @@ export class TypeScriptVersionManager extends Disposable {
private get useWorkspaceTsdkSetting(): boolean {
return this.workspaceState.get<boolean>(useWorkspaceTsdkStorageKey, false);
}

private get suppressPromptWorkspaceTsdkSetting(): boolean {
return this.workspaceState.get<boolean>(suppressPromptWorkspaceTsdkStorageKey, false);
}

private isInPromptWorkspaceTsdkState(configuration: TypeScriptServiceConfiguration) {
return (
configuration.localTsdk !== null
&& configuration.enablePromptUseWorkspaceTsdk === true
&& this.suppressPromptWorkspaceTsdkSetting === false
&& this.useWorkspaceTsdkSetting === false
);
}
}

const LearnMorePickItem: QuickPickItem = {
Expand Down