Skip to content

Commit c7c2301

Browse files
DuncanWalterDuncan Walter
andauthored
TS: Add setting to prompt users about workspace tsdk (microsoft#95566)
* add a setting to prompt users to switch to tsdk version * version manager in control Co-authored-by: Duncan Walter <dwalter@hubspot.com>
1 parent 4b178bf commit c7c2301

5 files changed

Lines changed: 80 additions & 5 deletions

File tree

extensions/typescript-language-features/package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,12 @@
140140
"usesOnlineServices"
141141
]
142142
},
143+
"typescript.enablePromptUseWorkspaceTsdk": {
144+
"type": "boolean",
145+
"default": false,
146+
"description": "%typescript.enablePromptUseWorkspaceTsdk%",
147+
"scope": "window"
148+
},
143149
"typescript.npm": {
144150
"type": [
145151
"string",

extensions/typescript-language-features/package.nls.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"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.",
88
"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.",
99
"typescript.disableAutomaticTypeAcquisition": "Disables automatic type acquisition. Automatic type acquisition fetches `@types` packages from npm to improve IntelliSense for external libraries.",
10+
"typescript.enablePromptUseWorkspaceTsdk": "Enables prompting of users to use the TypeScript version configured in the workspace for Intellisense.",
1011
"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.",
1112
"typescript.tsserver.pluginPaths": "Additional paths to discover TypeScript Language Service plugins. Requires using TypeScript 2.3.0 or newer in the workspace.",
1213
"typescript.tsserver.pluginPaths.item": "Either an absolute or relative path. Relative path will be resolved against workspace folder(s).",

extensions/typescript-language-features/src/typescriptServiceClient.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType
140140
this._configuration = TypeScriptServiceConfiguration.loadFromWorkspace();
141141
this.versionProvider = new TypeScriptVersionProvider(this._configuration);
142142
this.pluginPathsProvider = new TypeScriptPluginPathsProvider(this._configuration);
143-
this._versionManager = this._register(new TypeScriptVersionManager(this.versionProvider, this.workspaceState));
143+
this._versionManager = this._register(new TypeScriptVersionManager(this._configuration, this.versionProvider, this.workspaceState));
144144
this._register(this._versionManager.onDidPickNewVersion(() => {
145145
this.restartTsServer();
146146
}));
@@ -163,6 +163,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType
163163
this._configuration = TypeScriptServiceConfiguration.loadFromWorkspace();
164164

165165
this.versionProvider.updateConfiguration(this._configuration);
166+
this._versionManager.updateConfiguration(this._configuration);
166167
this.pluginPathsProvider.updateConfiguration(this._configuration);
167168
this.tracer.updateConfiguration();
168169

extensions/typescript-language-features/src/utils/configuration.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export class TypeScriptServiceConfiguration {
5959
public readonly useSeparateSyntaxServer: boolean;
6060
public readonly enableProjectDiagnostics: boolean;
6161
public readonly maxTsServerMemory: number;
62+
public readonly enablePromptUseWorkspaceTsdk: boolean;
6263
public readonly watchOptions: protocol.WatchOptions | undefined;
6364

6465
public static loadFromWorkspace(): TypeScriptServiceConfiguration {
@@ -80,6 +81,7 @@ export class TypeScriptServiceConfiguration {
8081
this.useSeparateSyntaxServer = TypeScriptServiceConfiguration.readUseSeparateSyntaxServer(configuration);
8182
this.enableProjectDiagnostics = TypeScriptServiceConfiguration.readEnableProjectDiagnostics(configuration);
8283
this.maxTsServerMemory = TypeScriptServiceConfiguration.readMaxTsServerMemory(configuration);
84+
this.enablePromptUseWorkspaceTsdk = TypeScriptServiceConfiguration.readEnablePromptUseWorkspaceTsdk(configuration);
8385
this.watchOptions = TypeScriptServiceConfiguration.readWatchOptions(configuration);
8486
}
8587

@@ -96,7 +98,8 @@ export class TypeScriptServiceConfiguration {
9698
&& this.useSeparateSyntaxServer === other.useSeparateSyntaxServer
9799
&& this.enableProjectDiagnostics === other.enableProjectDiagnostics
98100
&& this.maxTsServerMemory === other.maxTsServerMemory
99-
&& objects.equals(this.watchOptions, other.watchOptions);
101+
&& objects.equals(this.watchOptions, other.watchOptions)
102+
&& this.enablePromptUseWorkspaceTsdk === other.enablePromptUseWorkspaceTsdk;
100103
}
101104

102105
private static fixPathPrefixes(inspectValue: string): string {
@@ -175,4 +178,8 @@ export class TypeScriptServiceConfiguration {
175178
}
176179
return Math.max(memoryInMB, minimumMaxMemory);
177180
}
181+
182+
private static readEnablePromptUseWorkspaceTsdk(configuration: vscode.WorkspaceConfiguration): boolean {
183+
return configuration.get<boolean>('typescript.enablePromptUseWorkspaceTsdk', false);
184+
}
178185
}

extensions/typescript-language-features/src/utils/versionManager.ts

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ import * as vscode from 'vscode';
77
import * as nls from 'vscode-nls';
88
import { TypeScriptVersion, TypeScriptVersionProvider } from './versionProvider';
99
import { Disposable } from './dispose';
10+
import { TypeScriptServiceConfiguration } from '../utils/configuration';
1011

1112
const localize = nls.loadMessageBundle();
1213

1314
const useWorkspaceTsdkStorageKey = 'typescript.useWorkspaceTsdk';
15+
const suppressPromptWorkspaceTsdkStorageKey = 'typescript.suppressPromptWorkspaceTsdk';
1416

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

2325
public constructor(
26+
private configuration: TypeScriptServiceConfiguration,
2427
private readonly versionProvider: TypeScriptVersionProvider,
2528
private readonly workspaceState: vscode.Memento
2629
) {
@@ -34,11 +37,30 @@ export class TypeScriptVersionManager extends Disposable {
3437
this._currentVersion = localVersion;
3538
}
3639
}
40+
41+
if (this.isInPromptWorkspaceTsdkState(configuration)) {
42+
setImmediate(() => {
43+
this.promptUseWorkspaceTsdk();
44+
});
45+
}
46+
3747
}
3848

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

52+
public updateConfiguration(nextConfiguration: TypeScriptServiceConfiguration) {
53+
const lastConfiguration = this.configuration;
54+
this.configuration = nextConfiguration;
55+
56+
if (
57+
!this.isInPromptWorkspaceTsdkState(lastConfiguration)
58+
&& this.isInPromptWorkspaceTsdkState(nextConfiguration)
59+
) {
60+
this.promptUseWorkspaceTsdk();
61+
}
62+
}
63+
4264
public get currentVersion(): TypeScriptVersion {
4365
return this._currentVersion;
4466
}
@@ -71,7 +93,7 @@ export class TypeScriptVersionManager extends Disposable {
7193
detail: bundledVersion.pathLabel,
7294
run: async () => {
7395
await this.workspaceState.update(useWorkspaceTsdkStorageKey, false);
74-
this.updateForPickedVersion(bundledVersion);
96+
this.updateActiveVersion(bundledVersion);
7597
},
7698
};
7799
}
@@ -88,13 +110,38 @@ export class TypeScriptVersionManager extends Disposable {
88110
await this.workspaceState.update(useWorkspaceTsdkStorageKey, true);
89111
const tsConfig = vscode.workspace.getConfiguration('typescript');
90112
await tsConfig.update('tsdk', version.pathLabel, false);
91-
this.updateForPickedVersion(version);
113+
this.updateActiveVersion(version);
92114
},
93115
};
94116
});
95117
}
96118

97-
private updateForPickedVersion(pickedVersion: TypeScriptVersion) {
119+
private async promptUseWorkspaceTsdk(): Promise<void> {
120+
const workspaceVersion = this.versionProvider.localVersion;
121+
122+
if (workspaceVersion === undefined) {
123+
throw new Error('Could not prompt to use workspace TypeScript version because no workspace version is specified');
124+
}
125+
126+
const allowIt = localize('allow', 'Allow');
127+
const dismissPrompt = localize('dismiss', 'Dismiss');
128+
const suppressPrompt = localize('suppress prompt', 'Never in this Workspace');
129+
130+
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?'),
131+
allowIt,
132+
dismissPrompt,
133+
suppressPrompt
134+
);
135+
136+
if (result === allowIt) {
137+
await this.workspaceState.update(useWorkspaceTsdkStorageKey, true);
138+
this.updateActiveVersion(workspaceVersion);
139+
} else if (result === suppressPrompt) {
140+
await this.workspaceState.update(suppressPromptWorkspaceTsdkStorageKey, true);
141+
}
142+
}
143+
144+
private updateActiveVersion(pickedVersion: TypeScriptVersion) {
98145
const oldVersion = this.currentVersion;
99146
this._currentVersion = pickedVersion;
100147
if (!oldVersion.eq(pickedVersion)) {
@@ -105,6 +152,19 @@ export class TypeScriptVersionManager extends Disposable {
105152
private get useWorkspaceTsdkSetting(): boolean {
106153
return this.workspaceState.get<boolean>(useWorkspaceTsdkStorageKey, false);
107154
}
155+
156+
private get suppressPromptWorkspaceTsdkSetting(): boolean {
157+
return this.workspaceState.get<boolean>(suppressPromptWorkspaceTsdkStorageKey, false);
158+
}
159+
160+
private isInPromptWorkspaceTsdkState(configuration: TypeScriptServiceConfiguration) {
161+
return (
162+
configuration.localTsdk !== null
163+
&& configuration.enablePromptUseWorkspaceTsdk === true
164+
&& this.suppressPromptWorkspaceTsdkSetting === false
165+
&& this.useWorkspaceTsdkSetting === false
166+
);
167+
}
108168
}
109169

110170
const LearnMorePickItem: QuickPickItem = {

0 commit comments

Comments
 (0)