-
Notifications
You must be signed in to change notification settings - Fork 30.4k
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
Add custom Node option to run TS Server #191019
Changes from 7 commits
7de74a6
5f288d7
080e16a
d32c60e
17a3c23
f8fcc17
b3830ba
8210f67
ac96741
5d9c2bf
2c2e2d7
5944aae
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
/*--------------------------------------------------------------------------------------------- | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for license information. | ||
*--------------------------------------------------------------------------------------------*/ | ||
|
||
import * as vscode from 'vscode'; | ||
import { TypeScriptServiceConfiguration } from '../configuration/configuration'; | ||
import { setImmediate } from '../utils/async'; | ||
import { Disposable } from '../utils/dispose'; | ||
|
||
|
||
const useWorkspaceNodeStorageKey = 'typescript.useWorkspaceNode'; | ||
|
||
export class NodeVersionManager extends Disposable { | ||
private _currentVersion: string | undefined; | ||
|
||
public constructor( | ||
private configuration: TypeScriptServiceConfiguration, | ||
private readonly workspaceState: vscode.Memento | ||
) { | ||
super(); | ||
|
||
this._currentVersion = this.configuration.globalNodePath || undefined; | ||
if (vscode.workspace.isTrusted) { | ||
if (this.configuration.localNodePath) { | ||
if (this.useWorkspaceNodeSetting === undefined) { | ||
setImmediate(() => { | ||
this.promptAndSetWorkspaceNode(); | ||
}); | ||
} | ||
else if (this.useWorkspaceNodeSetting) { | ||
this._currentVersion = this.configuration.localNodePath; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This code looks the same as the code in the block below; probably could be pulled out into a method. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. They're the same except the version below uses |
||
} | ||
} | ||
else { | ||
this._disposables.push(vscode.workspace.onDidGrantWorkspaceTrust(() => { | ||
if (this.configuration.localNodePath) { | ||
if (this.useWorkspaceNodeSetting === undefined) { | ||
setImmediate(() => { | ||
this.promptAndSetWorkspaceNode(); | ||
}); | ||
} | ||
else if (this.useWorkspaceNodeSetting) { | ||
this.updateActiveVersion(this.configuration.localNodePath); | ||
} | ||
} | ||
})); | ||
} | ||
} | ||
|
||
private readonly _onDidPickNewVersion = this._register(new vscode.EventEmitter<void>()); | ||
public readonly onDidPickNewVersion = this._onDidPickNewVersion.event; | ||
|
||
public get currentVersion(): string | undefined { | ||
return this._currentVersion; | ||
} | ||
|
||
public reset(): void { | ||
this._currentVersion = undefined; | ||
} | ||
|
||
public async updateConfiguration(nextConfiguration: TypeScriptServiceConfiguration) { | ||
const oldConfiguration = this.configuration; | ||
this.configuration = nextConfiguration; | ||
if (oldConfiguration.globalNodePath !== nextConfiguration.globalNodePath | ||
|| oldConfiguration.localNodePath !== nextConfiguration.localNodePath) { | ||
await this.computeNewVersion(); | ||
} | ||
} | ||
|
||
private async computeNewVersion() { | ||
let version = this.configuration.globalNodePath || undefined; | ||
if (vscode.workspace.isTrusted && this.configuration.localNodePath) { | ||
if (this.useWorkspaceNodeSetting === undefined) { | ||
version = await this.promptUseWorkspaceNode(); | ||
} | ||
else if (this.useWorkspaceNodeSetting) { | ||
version = this.configuration.localNodePath; | ||
} | ||
} | ||
this.updateActiveVersion(version); | ||
} | ||
|
||
private async promptUseWorkspaceNode(): Promise<string | undefined> { | ||
const workspaceVersion = this.configuration.localNodePath; | ||
|
||
if (workspaceVersion === null) { | ||
throw new Error('Could not prompt to use workspace Node installation because no workspace Node installation is specified'); | ||
} | ||
|
||
const allow = vscode.l10n.t("Allow"); | ||
const dismiss = vscode.l10n.t("Dismiss"); | ||
const neverAllow = vscode.l10n.t("Never in this workspace"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Once the user selects There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I updated the code to remember the prompt answer for a specific node path. So if you change the workspace node path to point to a different path, the prompt will show up again. However, it's a bit contrived to do that if you select "never" by accident. Should I add a command to use the workspace node path? |
||
|
||
const result = await vscode.window.showInformationMessage(vscode.l10n.t("This workspace specifies a custom Node installation to run TS Server. Would you like to use this workspace's custom Node installation to run TS Server?"), | ||
allow, | ||
dismiss, | ||
neverAllow | ||
); | ||
|
||
let version = undefined; | ||
if (result === allow) { | ||
await this.workspaceState.update(useWorkspaceNodeStorageKey, true); | ||
version = workspaceVersion; | ||
} else if (result === neverAllow) { | ||
await this.workspaceState.update(useWorkspaceNodeStorageKey, false); | ||
} | ||
return version; | ||
} | ||
|
||
private async promptAndSetWorkspaceNode(): Promise<void> { | ||
const version = await this.promptUseWorkspaceNode(); | ||
if (version !== undefined) { | ||
this.updateActiveVersion(version); | ||
} | ||
} | ||
|
||
private updateActiveVersion(pickedVersion: string | undefined): void { | ||
const oldVersion = this.currentVersion; | ||
this._currentVersion = pickedVersion; | ||
if (oldVersion !== pickedVersion) { | ||
this._onDidPickNewVersion.fire(); | ||
} | ||
} | ||
|
||
private get useWorkspaceNodeSetting(): boolean | undefined { | ||
return this.workspaceState.get<boolean>(useWorkspaceNodeStorageKey); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume the "version" moniker is left over from copying the tsdk code? Was confused as to whether or not this was checking versions or something until I realized that this was acutally managing the node path.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, do you think simply
NodeManager
would be better?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was imagining
NodePathManager
and_currentPath
, but I also haven't gone to look for examples that would indicate what's canonical to this repo's style.