From 6e3fb280ec633ebd6e784e22fb097d82aeb6419e Mon Sep 17 00:00:00 2001 From: Andy Jordan Date: Mon, 31 Oct 2022 11:55:17 -0700 Subject: [PATCH 1/9] Remove unused `INotebooksSettings` This feature never made it out of preview. --- src/settings.ts | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/settings.ts b/src/settings.ts index 6a64992ce3..4ca91de4f7 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -98,7 +98,6 @@ export interface ISettings { pester: IPesterSettings; buttons?: IButtonSettings; cwd?: string; - notebooks?: INotebooksSettings; enableReferencesCodeLens?: boolean; analyzeOpenDocumentsOnly?: boolean; } @@ -132,10 +131,6 @@ export interface IButtonSettings { showPanelMovementButtons?: boolean; } -export interface INotebooksSettings { - saveMarkdownCellsAs?: CommentType; -} - // TODO: This could probably be async, and call `validateCwdSetting()` directly. export function load(): ISettings { const configuration: vscode.WorkspaceConfiguration = @@ -219,10 +214,6 @@ export function load(): ISettings { debugOutputVerbosity: "Diagnostic", }; - const defaultNotebooksSettings: INotebooksSettings = { - saveMarkdownCellsAs: CommentType.BlockComment, - }; - // TODO: I believe all the defaults can be removed, as the `package.json` should supply them (and be the source of truth). return { startAutomatically: @@ -261,8 +252,6 @@ export function load(): ISettings { configuration.get("pester", defaultPesterSettings), buttons: configuration.get("buttons", defaultButtonSettings), - notebooks: - configuration.get("notebooks", defaultNotebooksSettings), startAsLoginShell: // We follow the same convention as VS Code - https://github.com/microsoft/vscode/blob/ff00badd955d6cfcb8eab5f25f3edc86b762f49f/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts#L105-L107 // "Unlike on Linux, ~/.profile is not sourced when logging into a macOS session. This From 91bf1ab1fa328e8862548eae255b5af33adfd012 Mon Sep 17 00:00:00 2001 From: Andy Jordan Date: Mon, 31 Oct 2022 13:03:48 -0700 Subject: [PATCH 2/9] Remove unnecessary optional markings from `Settings` --- package.json | 2 +- src/process.ts | 2 +- src/settings.ts | 51 +++++++++++++++++++++++++------------------------ 3 files changed, 28 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index 3177d41d0c..be02a0eda5 100644 --- a/package.json +++ b/package.json @@ -816,7 +816,7 @@ "powershell.integratedConsole.suppressStartupBanner": { "type": "boolean", "default": false, - "description": "Do not show the Powershell Extension Terminal banner on launch" + "description": "Do not show the PowerShell Extension Terminal banner on launch." }, "powershell.debugging.createTemporaryIntegratedConsole": { "type": "boolean", diff --git a/src/process.ts b/src/process.ts index d6da4dc10f..c3458cba38 100644 --- a/src/process.ts +++ b/src/process.ts @@ -46,7 +46,7 @@ export class PowerShellProcess { "PowerShellEditorServices/PowerShellEditorServices.psd1"); const featureFlags = - this.sessionSettings.developer.featureFlags !== undefined + this.sessionSettings.developer.featureFlags.length > 0 ? this.sessionSettings.developer.featureFlags.map((f) => `'${f}'`).join(", ") : ""; diff --git a/src/settings.ts b/src/settings.ts index 4ca91de4f7..347d357dd8 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -33,8 +33,8 @@ export interface IBugReportingSettings { } export interface ICodeFoldingSettings { - enable?: boolean; - showLastLine?: boolean; + enable: boolean; + showLastLine: boolean; } export interface ICodeFormattingSettings { @@ -60,46 +60,46 @@ export interface ICodeFormattingSettings { } export interface IScriptAnalysisSettings { - enable?: boolean; + enable: boolean; settingsPath: string; } export interface IDebuggingSettings { - createTemporaryIntegratedConsole?: boolean; + createTemporaryIntegratedConsole: boolean; } export interface IDeveloperSettings { - featureFlags?: string[]; + featureFlags: string[]; bundledModulesPath: string; editorServicesLogLevel: string; - editorServicesWaitForDebugger?: boolean; + editorServicesWaitForDebugger: boolean; waitForSessionFileTimeoutSeconds: number; } export interface ISettings { - powerShellAdditionalExePaths?: IPowerShellAdditionalExePathSettings; - powerShellDefaultVersion?: string; + powerShellAdditionalExePaths: IPowerShellAdditionalExePathSettings | undefined; + powerShellDefaultVersion: string | undefined; // This setting is no longer used but is here to assist in cleaning up the users settings. - powerShellExePath?: string; - promptToUpdatePowerShell?: boolean; + powerShellExePath: string | undefined; + promptToUpdatePowerShell: boolean; bundledModulesPath: string; startAsLoginShell: IStartAsLoginShellSettings; - startAutomatically?: boolean; + startAutomatically: boolean; enableProfileLoading: boolean; helpCompletion: string; - scriptAnalysis?: IScriptAnalysisSettings; + scriptAnalysis: IScriptAnalysisSettings; debugging: IDebuggingSettings; developer: IDeveloperSettings; - codeFolding?: ICodeFoldingSettings; - codeFormatting?: ICodeFormattingSettings; + codeFolding: ICodeFoldingSettings; + codeFormatting: ICodeFormattingSettings; integratedConsole: IIntegratedConsoleSettings; bugReporting: IBugReportingSettings; sideBar: ISideBarSettings; pester: IPesterSettings; - buttons?: IButtonSettings; - cwd?: string; - enableReferencesCodeLens?: boolean; - analyzeOpenDocumentsOnly?: boolean; + buttons: IButtonSettings; + cwd: string | undefined; + enableReferencesCodeLens: boolean; + analyzeOpenDocumentsOnly: boolean; } export interface IStartAsLoginShellSettings { @@ -108,12 +108,12 @@ export interface IStartAsLoginShellSettings { } export interface IIntegratedConsoleSettings { - showOnStartup?: boolean; - startInBackground?: boolean; + showOnStartup: boolean; + startInBackground: boolean; focusConsoleOnExecute: boolean; - useLegacyReadLine?: boolean; - forceClearScrollbackBuffer?: boolean; - suppressStartupBanner?: boolean; + useLegacyReadLine: boolean; + forceClearScrollbackBuffer: boolean; + suppressStartupBanner: boolean; } export interface ISideBarSettings { @@ -127,8 +127,8 @@ export interface IPesterSettings { } export interface IButtonSettings { - showRunButtons?: boolean; - showPanelMovementButtons?: boolean; + showRunButtons: boolean; + showPanelMovementButtons: boolean; } // TODO: This could probably be async, and call `validateCwdSetting()` directly. @@ -197,6 +197,7 @@ export function load(): ISettings { focusConsoleOnExecute: true, useLegacyReadLine: false, forceClearScrollbackBuffer: false, + suppressStartupBanner: false, }; const defaultSideBarSettings: ISideBarSettings = { From e431f79181d725c519f7f3e2030c09aec5d6f75d Mon Sep 17 00:00:00 2001 From: Andy Jordan Date: Wed, 2 Nov 2022 12:54:44 -0700 Subject: [PATCH 3/9] Make setting defaults consistent and remove `bundledModulesPath` setting This wasn't a "setting" anyway because it wasn't settable. --- package.json | 4 ++-- src/session.ts | 5 +++-- src/settings.ts | 31 ++++++++++--------------------- 3 files changed, 15 insertions(+), 25 deletions(-) diff --git a/package.json b/package.json index be02a0eda5..1c5cbf24f2 100644 --- a/package.json +++ b/package.json @@ -584,7 +584,6 @@ }, "powershell.powerShellExePath": { "type": "string", - "default": "", "scope": "machine", "description": "REMOVED: Please use the \"powershell.powerShellAdditionalExePaths\" setting instead.", "deprecationMessage": "Please use the \"powershell.powerShellAdditionalExePaths\" setting instead." @@ -653,7 +652,6 @@ }, "powershell.cwd": { "type": "string", - "default": null, "description": "An explicit start path where the PowerShell Extension Terminal will be launched. Both the PowerShell process's and the shell's location will be set to this directory. A fully resolved path must be provided!" }, "powershell.scriptAnalysis.enable": { @@ -811,6 +809,7 @@ }, "powershell.integratedConsole.forceClearScrollbackBuffer": { "type": "boolean", + "default": false, "description": "Use the vscode API to clear the terminal since that's the only reliable way to clear the scrollback buffer. Turn this on if you're used to 'Clear-Host' clearing scroll history as well as clear-terminal-via-lsp." }, "powershell.integratedConsole.suppressStartupBanner": { @@ -825,6 +824,7 @@ }, "powershell.developer.bundledModulesPath": { "type": "string", + "default": "../../PowerShellEditorServices/module", "description": "Specifies an alternate path to the folder containing modules that are bundled with the PowerShell extension (i.e. PowerShell Editor Services, PSScriptAnalyzer, Plaster)" }, "powershell.developer.editorServicesLogLevel": { diff --git a/src/session.ts b/src/session.ts index e771ef9343..c27dabbc46 100644 --- a/src/session.ts +++ b/src/session.ts @@ -525,13 +525,14 @@ export class SessionManager implements Middleware { } private async getBundledModulesPath(): Promise { - let bundledModulesPath = path.resolve(__dirname, this.sessionSettings.bundledModulesPath); + // Because the extension is always at `/out/main.js` + let bundledModulesPath = path.resolve(__dirname, "../modules"); if (this.extensionContext.extensionMode === vscode.ExtensionMode.Development) { const devBundledModulesPath = path.resolve(__dirname, this.sessionSettings.developer.bundledModulesPath); // Make sure the module's bin path exists - if (await utils.checkIfDirectoryExists(path.join(devBundledModulesPath, "PowerShellEditorServices/bin"))) { + if (await utils.checkIfDirectoryExists(devBundledModulesPath)) { bundledModulesPath = devBundledModulesPath; } else { void this.logger.writeAndShowWarning( diff --git a/src/settings.ts b/src/settings.ts index 347d357dd8..d7b0764980 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -82,7 +82,6 @@ export interface ISettings { // This setting is no longer used but is here to assist in cleaning up the users settings. powerShellExePath: string | undefined; promptToUpdatePowerShell: boolean; - bundledModulesPath: string; startAsLoginShell: IStartAsLoginShellSettings; startAutomatically: boolean; enableProfileLoading: boolean; @@ -117,10 +116,12 @@ export interface IIntegratedConsoleSettings { } export interface ISideBarSettings { + // TODO: add CommandExplorerExcludeFilter CommandExplorerVisibility: boolean; } export interface IPesterSettings { + // TODO: add codeLens property useLegacyCodeLens: boolean; outputVerbosity: string; debugOutputVerbosity: string; @@ -161,7 +162,7 @@ export function load(): ISettings { const defaultCodeFoldingSettings: ICodeFoldingSettings = { enable: true, - showLastLine: false, + showLastLine: true, }; const defaultCodeFormattingSettings: ICodeFormattingSettings = { @@ -215,7 +216,10 @@ export function load(): ISettings { debugOutputVerbosity: "Diagnostic", }; - // TODO: I believe all the defaults can be removed, as the `package.json` should supply them (and be the source of truth). + // TODO: I believe all the defaults can be removed, as the `package.json` + // should supply them (and be the source of truth). However, this proves + // fairly messy to do as it requires casting the configuration to unknown + // and then to `ISettings`. It could work but will take more testing. return { startAutomatically: configuration.get("startAutomatically", true), @@ -227,10 +231,8 @@ export function load(): ISettings { configuration.get("powerShellExePath"), promptToUpdatePowerShell: configuration.get("promptToUpdatePowerShell", true), - bundledModulesPath: - "../modules", // Because the extension is always at `/out/main.js` enableProfileLoading: - configuration.get("enableProfileLoading", false), + configuration.get("enableProfileLoading", true), helpCompletion: configuration.get("helpCompletion", CommentType.BlockComment), scriptAnalysis: @@ -238,7 +240,7 @@ export function load(): ISettings { debugging: configuration.get("debugging", defaultDebuggingSettings), developer: - getWorkspaceSettingsWithDefaults(configuration, "developer", defaultDeveloperSettings), + configuration.get("developer", defaultDeveloperSettings), codeFolding: configuration.get("codeFolding", defaultCodeFoldingSettings), codeFormatting: @@ -264,7 +266,7 @@ export function load(): ISettings { enableReferencesCodeLens: configuration.get("enableReferencesCodeLens", true), analyzeOpenDocumentsOnly: - configuration.get("analyzeOpenDocumentsOnly", true), + configuration.get("analyzeOpenDocumentsOnly", false), }; } @@ -303,19 +305,6 @@ export async function change( } } -function getWorkspaceSettingsWithDefaults( - workspaceConfiguration: vscode.WorkspaceConfiguration, - settingName: string, - defaultSettings: TSettings): TSettings { - - const importedSettings: TSettings = workspaceConfiguration.get(settingName, defaultSettings); - - for (const setting in importedSettings) { - defaultSettings[setting] = importedSettings[setting]; - } - return defaultSettings; -} - // We don't want to query the user more than once, so this is idempotent. let hasPrompted = false; From 99dee72668998d21eb12024d7ece2f552ab14fe3 Mon Sep 17 00:00:00 2001 From: Andy Jordan Date: Wed, 2 Nov 2022 12:56:17 -0700 Subject: [PATCH 4/9] Clean up `settings.ts` and its use --- src/features/Console.ts | 4 +- src/features/DebugSession.ts | 4 +- src/features/ExtensionCommands.ts | 4 +- src/features/GenerateBugReport.ts | 5 +- src/features/HelpCompletion.ts | 14 ++--- src/features/ISECompatibility.ts | 4 +- src/features/PesterTests.ts | 4 +- src/features/RunCode.ts | 4 +- src/features/UpdatePowerShell.ts | 4 +- src/main.ts | 8 +-- src/session.ts | 28 +++++----- src/settings.ts | 91 +++++++++++++++++-------------- test/core/settings.test.ts | 16 +++--- 13 files changed, 98 insertions(+), 92 deletions(-) diff --git a/src/features/Console.ts b/src/features/Console.ts index 279a981127..6569fe1b9e 100644 --- a/src/features/Console.ts +++ b/src/features/Console.ts @@ -6,7 +6,7 @@ import { NotificationType, RequestType } from "vscode-languageclient"; import { LanguageClient } from "vscode-languageclient/node"; import { ICheckboxQuickPickItem, showCheckboxQuickPick } from "../controls/checkboxQuickPick"; import { Logger } from "../logging"; -import Settings = require("../settings"); +import { getSettings } from "../settings"; import { LanguageClientConsumer } from "../languageClientConsumer"; export const EvaluateRequestType = new RequestType("evaluate"); @@ -182,7 +182,7 @@ export class ConsoleFeature extends LanguageClientConsumer { // We need to honor the focusConsoleOnExecute setting here too. However, the boolean that `show` // takes is called `preserveFocus` which when `true` the terminal will not take focus. // This is the inverse of focusConsoleOnExecute so we have to inverse the boolean. - vscode.window.activeTerminal.show(!Settings.load().integratedConsole.focusConsoleOnExecute); + vscode.window.activeTerminal.show(!getSettings().integratedConsole.focusConsoleOnExecute); await vscode.commands.executeCommand("workbench.action.terminal.scrollToBottom"); return; diff --git a/src/features/DebugSession.ts b/src/features/DebugSession.ts index 39d90f097a..db79bce515 100644 --- a/src/features/DebugSession.ts +++ b/src/features/DebugSession.ts @@ -11,7 +11,7 @@ import { LanguageClient } from "vscode-languageclient/node"; import { getPlatformDetails, OperatingSystem } from "../platform"; import { PowerShellProcess } from "../process"; import { IEditorServicesSessionDetails, SessionManager, SessionStatus } from "../session"; -import Settings = require("../settings"); +import { getSettings } from "../settings"; import { Logger } from "../logging"; import { LanguageClientConsumer } from "../languageClientConsumer"; import path = require("path"); @@ -169,7 +169,7 @@ export class DebugSessionFeature extends LanguageClientConsumer // setting. Otherwise, the launch config value overrides the setting. // // Also start the temporary process and console for this configuration. - const settings = Settings.load(); + const settings = getSettings(); config.createTemporaryIntegratedConsole = config.createTemporaryIntegratedConsole ?? settings.debugging.createTemporaryIntegratedConsole; diff --git a/src/features/ExtensionCommands.ts b/src/features/ExtensionCommands.ts index c62dde9bc1..9d43ce2cf1 100644 --- a/src/features/ExtensionCommands.ts +++ b/src/features/ExtensionCommands.ts @@ -10,7 +10,7 @@ import { } from "vscode-languageclient"; import { LanguageClient } from "vscode-languageclient/node"; import { Logger } from "../logging"; -import Settings = require("../settings"); +import { getSettings } from "../settings"; import { LanguageClientConsumer } from "../languageClientConsumer"; export interface IExtensionCommand { @@ -260,7 +260,7 @@ export class ExtensionCommandsFeature extends LanguageClientConsumer { () => { // We check to see if they have TrueClear on. If not, no-op because the // overriden Clear-Host already calls [System.Console]::Clear() - if (Settings.load().integratedConsole.forceClearScrollbackBuffer) { + if (getSettings().integratedConsole.forceClearScrollbackBuffer) { void vscode.commands.executeCommand("workbench.action.terminal.clear"); } }) diff --git a/src/features/GenerateBugReport.ts b/src/features/GenerateBugReport.ts index d7db34c500..f1a50751f7 100644 --- a/src/features/GenerateBugReport.ts +++ b/src/features/GenerateBugReport.ts @@ -5,12 +5,11 @@ import os = require("os"); import vscode = require("vscode"); import child_process = require("child_process"); import { SessionManager } from "../session"; -import Settings = require("../settings"); +import { getSettings } from "../settings"; const queryStringPrefix = "?"; -const settings = Settings.load(); -const project = settings.bugReporting.project; +const project = getSettings().bugReporting.project; const issuesUrl = `${project}/issues/new`; const extensions = diff --git a/src/features/HelpCompletion.ts b/src/features/HelpCompletion.ts index ec64795743..8bbf14d578 100644 --- a/src/features/HelpCompletion.ts +++ b/src/features/HelpCompletion.ts @@ -7,7 +7,7 @@ import { } from "vscode"; import { RequestType } from "vscode-languageclient"; import { LanguageClient } from "vscode-languageclient/node"; -import Settings = require("../settings"); +import { ISettings, CommentType, getSettings } from "../settings"; import { LanguageClientConsumer } from "../languageClientConsumer"; // eslint-disable-next-line @typescript-eslint/no-empty-interface @@ -27,13 +27,13 @@ enum SearchState { Searching, Locked, Found } export class HelpCompletionFeature extends LanguageClientConsumer { private helpCompletionProvider: HelpCompletionProvider | undefined; private disposable: Disposable | undefined; - private settings: Settings.ISettings; + private settings: ISettings; constructor() { super(); - this.settings = Settings.load(); + this.settings = getSettings(); - if (this.settings.helpCompletion !== Settings.CommentType.Disabled) { + if (this.settings.helpCompletion !== CommentType.Disabled) { this.helpCompletionProvider = new HelpCompletionProvider(); this.disposable = workspace.onDidChangeTextDocument(async (e) => { await this.onEvent(e); }); } @@ -125,11 +125,11 @@ class HelpCompletionProvider { private lastChangeRange: Range | undefined; private lastDocument: TextDocument | undefined; private langClient: LanguageClient | undefined; - private settings: Settings.ISettings; + private settings: ISettings; constructor() { this.triggerFinderHelpComment = new TriggerFinder("##"); - this.settings = Settings.load(); + this.settings = getSettings(); } public get triggerFound(): boolean { @@ -161,7 +161,7 @@ class HelpCompletionProvider { const result = await this.langClient.sendRequest(CommentHelpRequestType, { documentUri: doc.uri.toString(), triggerPosition: triggerStartPos, - blockComment: this.settings.helpCompletion === Settings.CommentType.BlockComment, + blockComment: this.settings.helpCompletion === CommentType.BlockComment, }); if (result.content.length === 0) { diff --git a/src/features/ISECompatibility.ts b/src/features/ISECompatibility.ts index 2dc052cc6e..0a4993ca69 100644 --- a/src/features/ISECompatibility.ts +++ b/src/features/ISECompatibility.ts @@ -2,7 +2,7 @@ // Licensed under the MIT License. import * as vscode from "vscode"; -import * as Settings from "../settings"; +import { getSettings } from "../settings"; interface ISetting { path: string; @@ -63,7 +63,7 @@ export class ISECompatibilityFeature implements vscode.Disposable { // Show the PowerShell view container which has the Command Explorer view await vscode.commands.executeCommand("workbench.view.extension.PowerShell"); - if (!Settings.load().sideBar.CommandExplorerVisibility) { + if (!getSettings().sideBar.CommandExplorerVisibility) { // Hide the explorer if the setting says so. await vscode.commands.executeCommand("workbench.action.toggleSidebarVisibility"); } diff --git a/src/features/PesterTests.ts b/src/features/PesterTests.ts index dc703254c0..4e4c55bda8 100644 --- a/src/features/PesterTests.ts +++ b/src/features/PesterTests.ts @@ -4,7 +4,7 @@ import * as path from "path"; import vscode = require("vscode"); import { SessionManager } from "../session"; -import Settings = require("../settings"); +import { getSettings } from "../settings"; import utils = require("../utils"); enum LaunchType { @@ -83,7 +83,7 @@ export class PesterTestsFeature implements vscode.Disposable { lineNum?: number, outputPath?: string): vscode.DebugConfiguration { - const settings = Settings.load(); + const settings = getSettings(); // Since we pass the script path to PSES in single quotes to avoid issues with PowerShell // special chars like & $ @ () [], we do have to double up the interior single quotes. diff --git a/src/features/RunCode.ts b/src/features/RunCode.ts index 269ceebe9c..2bd8424cbd 100644 --- a/src/features/RunCode.ts +++ b/src/features/RunCode.ts @@ -3,7 +3,7 @@ import vscode = require("vscode"); import { SessionManager } from "../session"; -import Settings = require("../settings"); +import { getSettings } from "../settings"; enum LaunchType { Debug, @@ -46,7 +46,7 @@ export class RunCodeFeature implements vscode.Disposable { } function createLaunchConfig(launchType: LaunchType, commandToRun: string, args: string[]) { - const settings = Settings.load(); + const settings = getSettings(); const launchConfig = { request: "launch", diff --git a/src/features/UpdatePowerShell.ts b/src/features/UpdatePowerShell.ts index aec794892f..2a83ccd547 100644 --- a/src/features/UpdatePowerShell.ts +++ b/src/features/UpdatePowerShell.ts @@ -14,7 +14,7 @@ import { MessageItem, ProgressLocation, window } from "vscode"; import { LanguageClient } from "vscode-languageclient/node"; import { Logger } from "../logging"; import { SessionManager } from "../session"; -import * as Settings from "../settings"; +import { changeSetting } from "../settings"; import { isMacOS, isWindows } from "../utils"; import { EvaluateRequestType } from "./Console"; @@ -195,7 +195,7 @@ export async function InvokePowerShellUpdateCheck( // Never choice. case 2: - await Settings.change("promptToUpdatePowerShell", false, true, logger); + await changeSetting("promptToUpdatePowerShell", false, true, logger); break; default: break; diff --git a/src/main.ts b/src/main.ts index e34ff062d7..800b51a69f 100644 --- a/src/main.ts +++ b/src/main.ts @@ -26,7 +26,7 @@ import { ShowHelpFeature } from "./features/ShowHelp"; import { SpecifyScriptArgsFeature } from "./features/DebugSession"; import { Logger } from "./logging"; import { SessionManager } from "./session"; -import Settings = require("./settings"); +import { LogLevel, getSettings, validateCwdSetting } from "./settings"; import { PowerShellLanguageId } from "./utils"; import { LanguageClientConsumer } from "./languageClientConsumer"; @@ -51,7 +51,7 @@ const documentSelector: DocumentSelector = [ export async function activate(context: vscode.ExtensionContext): Promise { const logLevel = vscode.workspace.getConfiguration(`${PowerShellLanguageId}.developer`) - .get("editorServicesLogLevel", "Normal"); + .get("editorServicesLogLevel", LogLevel.Normal); logger = new Logger(logLevel, context.globalStorageUri); telemetryReporter = new TelemetryReporter(PackageJSON.name, PackageJSON.version, AI_KEY); @@ -65,8 +65,8 @@ export async function activate(context: vscode.ExtensionContext): Promise { + public async createDebugSessionProcess(settings: ISettings): Promise { // NOTE: We only support one temporary Extension Terminal at a time. To // support more, we need to track each separately, and tie the session // for the event handler to the right process (and dispose of the event @@ -343,12 +343,12 @@ export class SessionManager implements Middleware { const configuration = vscode.workspace.getConfiguration(utils.PowerShellLanguageId); const deprecatedSetting = "codeFormatting.whitespaceAroundPipe"; const newSetting = "codeFormatting.addWhitespaceAroundPipe"; - const configurationTargetOfNewSetting = Settings.getEffectiveConfigurationTarget(newSetting); - const configurationTargetOfOldSetting = Settings.getEffectiveConfigurationTarget(deprecatedSetting); + const configurationTargetOfNewSetting = getEffectiveConfigurationTarget(newSetting); + const configurationTargetOfOldSetting = getEffectiveConfigurationTarget(deprecatedSetting); if (configurationTargetOfOldSetting !== undefined && configurationTargetOfNewSetting === undefined) { const value = configuration.get(deprecatedSetting, configurationTargetOfOldSetting); - await Settings.change(newSetting, value, configurationTargetOfOldSetting, this.logger); - await Settings.change(deprecatedSetting, undefined, configurationTargetOfOldSetting, this.logger); + await changeSetting(newSetting, value, configurationTargetOfOldSetting, this.logger); + await changeSetting(deprecatedSetting, undefined, configurationTargetOfOldSetting, this.logger); } } @@ -372,7 +372,7 @@ export class SessionManager implements Middleware { this.suppressRestartPrompt = true; try { - await Settings.change("powerShellExePath", undefined, true, this.logger); + await changeSetting("powerShellExePath", undefined, true, this.logger); } finally { this.suppressRestartPrompt = false; } @@ -384,7 +384,7 @@ export class SessionManager implements Middleware { } private async onConfigurationUpdated() { - const settings = Settings.load(); + const settings = getSettings(); this.logger.updateLogLevel(settings.developer.editorServicesLogLevel); // Detect any setting changes that would affect the session @@ -578,9 +578,7 @@ Type 'help' to get help. editorServicesArgs += "-WaitForDebugger "; } - if (this.sessionSettings.developer.editorServicesLogLevel) { - editorServicesArgs += `-LogLevel '${this.sessionSettings.developer.editorServicesLogLevel}' `; - } + editorServicesArgs += `-LogLevel '${this.sessionSettings.developer.editorServicesLogLevel}' `; return editorServicesArgs; } @@ -808,7 +806,7 @@ Type 'help' to get help. private async changePowerShellDefaultVersion(exePath: IPowerShellExeDetails) { this.suppressRestartPrompt = true; try { - await Settings.change("powerShellDefaultVersion", exePath.displayName, true, this.logger); + await changeSetting("powerShellDefaultVersion", exePath.displayName, true, this.logger); } finally { this.suppressRestartPrompt = false; } diff --git a/src/settings.ts b/src/settings.ts index d7b0764980..1cd5c2f75e 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -6,18 +6,53 @@ import utils = require("./utils"); import os = require("os"); import { Logger } from "./logging"; -enum CodeFormattingPreset { - Custom, - Allman, - OTBS, - Stroustrup, +export interface ISettings { + powerShellAdditionalExePaths: IPowerShellAdditionalExePathSettings | undefined; + powerShellDefaultVersion: string | undefined; + // This setting is no longer used but is here to assist in cleaning up the users settings. + powerShellExePath: string | undefined; + promptToUpdatePowerShell: boolean; + startAsLoginShell: IStartAsLoginShellSettings; + startAutomatically: boolean; + enableProfileLoading: boolean; + helpCompletion: string; + scriptAnalysis: IScriptAnalysisSettings; + debugging: IDebuggingSettings; + developer: IDeveloperSettings; + codeFolding: ICodeFoldingSettings; + codeFormatting: ICodeFormattingSettings; + integratedConsole: IIntegratedConsoleSettings; + bugReporting: IBugReportingSettings; + sideBar: ISideBarSettings; + pester: IPesterSettings; + buttons: IButtonSettings; + cwd: string | undefined; + enableReferencesCodeLens: boolean; + analyzeOpenDocumentsOnly: boolean; + // TODO: Add (deprecated) useX86Host (for testing) +} + +export enum CodeFormattingPreset { + Custom = "Custom", + Allman = "Allman", + OTBS = "OTBS", + Stroustrup = "Stroustrup", +} + +export enum PipelineIndentationStyle { + IncreaseIndentationForFirstPipeline = "IncreaseIndentationForFirstPipeline", + IncreaseIndentationAfterEveryPipeline = "IncreaseIndentationAfterEveryPipeline", + NoIndentation = "NoIndentation", + None = "None", } -enum PipelineIndentationStyle { - IncreaseIndentationForFirstPipeline, - IncreaseIndentationAfterEveryPipeline, - NoIndentation, - None, +export enum LogLevel { + Diagnostic = "Diagnostic", + Verbose = "Verbose", + Normal = "Normal", + Warning = "Warning", + Error = "Error", + None = "None", } export enum CommentType { @@ -71,36 +106,11 @@ export interface IDebuggingSettings { export interface IDeveloperSettings { featureFlags: string[]; bundledModulesPath: string; - editorServicesLogLevel: string; + editorServicesLogLevel: LogLevel; editorServicesWaitForDebugger: boolean; waitForSessionFileTimeoutSeconds: number; } -export interface ISettings { - powerShellAdditionalExePaths: IPowerShellAdditionalExePathSettings | undefined; - powerShellDefaultVersion: string | undefined; - // This setting is no longer used but is here to assist in cleaning up the users settings. - powerShellExePath: string | undefined; - promptToUpdatePowerShell: boolean; - startAsLoginShell: IStartAsLoginShellSettings; - startAutomatically: boolean; - enableProfileLoading: boolean; - helpCompletion: string; - scriptAnalysis: IScriptAnalysisSettings; - debugging: IDebuggingSettings; - developer: IDeveloperSettings; - codeFolding: ICodeFoldingSettings; - codeFormatting: ICodeFormattingSettings; - integratedConsole: IIntegratedConsoleSettings; - bugReporting: IBugReportingSettings; - sideBar: ISideBarSettings; - pester: IPesterSettings; - buttons: IButtonSettings; - cwd: string | undefined; - enableReferencesCodeLens: boolean; - analyzeOpenDocumentsOnly: boolean; -} - export interface IStartAsLoginShellSettings { osx: boolean; linux: boolean; @@ -132,8 +142,7 @@ export interface IButtonSettings { showPanelMovementButtons: boolean; } -// TODO: This could probably be async, and call `validateCwdSetting()` directly. -export function load(): ISettings { +export function getSettings(): ISettings { const configuration: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration(utils.PowerShellLanguageId); @@ -155,7 +164,7 @@ export function load(): ISettings { // From `/out/main.js` we go to the directory before and // then into the other repo. bundledModulesPath: "../../PowerShellEditorServices/module", - editorServicesLogLevel: "Normal", + editorServicesLogLevel: LogLevel.Normal, editorServicesWaitForDebugger: false, waitForSessionFileTimeoutSeconds: 240, }; @@ -288,7 +297,7 @@ export function getEffectiveConfigurationTarget(settingName: string): vscode.Con return undefined; } -export async function change( +export async function changeSetting( settingName: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any newValue: any, @@ -333,7 +342,7 @@ export async function validateCwdSetting(logger: Logger): Promise { // Save the picked 'cwd' to the workspace settings. // We have to check again because the user may not have picked. if (cwd !== undefined && await utils.checkIfDirectoryExists(cwd)) { - await change("cwd", cwd, undefined, logger); + await changeSetting("cwd", cwd, undefined, logger); } } diff --git a/test/core/settings.test.ts b/test/core/settings.test.ts index 8e9f771309..0ad76f920c 100644 --- a/test/core/settings.test.ts +++ b/test/core/settings.test.ts @@ -3,25 +3,25 @@ import * as assert from "assert"; import * as vscode from "vscode"; -import Settings = require("../../src/settings"); +import { CommentType, getSettings, changeSetting, getEffectiveConfigurationTarget } from "../../src/settings"; describe("Settings module", function () { it("Loads without error", function () { - assert.doesNotThrow(Settings.load); + assert.doesNotThrow(getSettings); }); it("Updates correctly", async function () { - await Settings.change("helpCompletion", "LineComment", false, undefined); - assert.strictEqual(Settings.load().helpCompletion, "LineComment"); + await changeSetting("helpCompletion", CommentType.LineComment, false, undefined); + assert.strictEqual(getSettings().helpCompletion, CommentType.LineComment); }); it("Gets the effective configuration target", async function () { - await Settings.change("helpCompletion", "LineComment", false, undefined); - let target = Settings.getEffectiveConfigurationTarget("helpCompletion"); + await changeSetting("helpCompletion", CommentType.LineComment, false, undefined); + let target = getEffectiveConfigurationTarget("helpCompletion"); assert.strictEqual(target, vscode.ConfigurationTarget.Workspace); - await Settings.change("helpCompletion", undefined, false, undefined); - target = Settings.getEffectiveConfigurationTarget("helpCompletion"); + await changeSetting("helpCompletion", undefined, false, undefined); + target = getEffectiveConfigurationTarget("helpCompletion"); assert.strictEqual(target, undefined); }); }); From 39abfd52a6055ab9fe61f63daab75282b76d6221 Mon Sep 17 00:00:00 2001 From: Andy Jordan Date: Wed, 2 Nov 2022 14:31:12 -0700 Subject: [PATCH 5/9] Automatically fill in `ISettings` from configuration Using recursion! With a test! --- package.json | 4 ++ src/session.ts | 10 ++-- src/settings.ts | 115 ++++++++++++++++++------------------- test/.vscode/settings.json | 3 + test/core/settings.test.ts | 25 +++++--- 5 files changed, 85 insertions(+), 72 deletions(-) diff --git a/package.json b/package.json index 1c5cbf24f2..5cdb477f26 100644 --- a/package.json +++ b/package.json @@ -573,6 +573,7 @@ }, "powershell.powerShellAdditionalExePaths": { "type": "object", + "default": {}, "description": "Specifies a list of versionName / exePath pairs where exePath points to a non-standard install location for PowerShell and versionName can be used to reference this path with the powershell.powerShellDefaultVersion setting.", "additionalProperties": { "type": "string" @@ -580,10 +581,12 @@ }, "powershell.powerShellDefaultVersion": { "type": "string", + "default": "", "description": "Specifies the PowerShell version name, as displayed by the 'PowerShell: Show Session Menu' command, used when the extension loads e.g \"Windows PowerShell (x86)\" or \"PowerShell Core 7 (x64)\". You can specify additional PowerShell executables by using the \"powershell.powerShellAdditionalExePaths\" setting." }, "powershell.powerShellExePath": { "type": "string", + "default": "", "scope": "machine", "description": "REMOVED: Please use the \"powershell.powerShellAdditionalExePaths\" setting instead.", "deprecationMessage": "Please use the \"powershell.powerShellAdditionalExePaths\" setting instead." @@ -652,6 +655,7 @@ }, "powershell.cwd": { "type": "string", + "default": "", "description": "An explicit start path where the PowerShell Extension Terminal will be launched. Both the PowerShell process's and the shell's location will be set to this directory. A fully resolved path must be provided!" }, "powershell.scriptAnalysis.enable": { diff --git a/src/session.ts b/src/session.ts index fdcd8cb85c..f27699bbe9 100644 --- a/src/session.ts +++ b/src/session.ts @@ -354,7 +354,7 @@ export class SessionManager implements Middleware { // TODO: Remove this migration code. private async promptPowerShellExeSettingsCleanup() { - if (!this.sessionSettings.powerShellExePath) { // undefined or null + if (this.sessionSettings.powerShellExePath === "") { return; } @@ -378,7 +378,7 @@ export class SessionManager implements Middleware { } // Show the session menu at the end if they don't have a PowerShellDefaultVersion. - if (this.sessionSettings.powerShellDefaultVersion === undefined) { + if (this.sessionSettings.powerShellDefaultVersion === "") { await vscode.commands.executeCommand(this.ShowSessionMenuCommandName); } } @@ -389,8 +389,8 @@ export class SessionManager implements Middleware { // Detect any setting changes that would affect the session if (!this.suppressRestartPrompt && - (settings.cwd?.toLowerCase() !== this.sessionSettings.cwd?.toLowerCase() - || settings.powerShellDefaultVersion?.toLowerCase() !== this.sessionSettings.powerShellDefaultVersion?.toLowerCase() + (settings.cwd.toLowerCase() !== this.sessionSettings.cwd.toLowerCase() + || settings.powerShellDefaultVersion.toLowerCase() !== this.sessionSettings.powerShellDefaultVersion.toLowerCase() || settings.developer.editorServicesLogLevel.toLowerCase() !== this.sessionSettings.developer.editorServicesLogLevel.toLowerCase() || settings.developer.bundledModulesPath.toLowerCase() !== this.sessionSettings.developer.bundledModulesPath.toLowerCase() || settings.integratedConsole.useLegacyReadLine !== this.sessionSettings.integratedConsole.useLegacyReadLine @@ -489,7 +489,7 @@ export class SessionManager implements Middleware { let foundPowerShell: IPowerShellExeDetails | undefined; try { let defaultPowerShell: IPowerShellExeDetails | undefined; - if (this.sessionSettings.powerShellDefaultVersion !== undefined) { + if (this.sessionSettings.powerShellDefaultVersion !== "") { for await (const details of powershellExeFinder.enumeratePowerShellInstallations()) { // Need to compare names case-insensitively, from https://stackoverflow.com/a/2140723 const wantedName = this.sessionSettings.powerShellDefaultVersion; diff --git a/src/settings.ts b/src/settings.ts index 1cd5c2f75e..1d97bab798 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -7,10 +7,10 @@ import os = require("os"); import { Logger } from "./logging"; export interface ISettings { - powerShellAdditionalExePaths: IPowerShellAdditionalExePathSettings | undefined; - powerShellDefaultVersion: string | undefined; + powerShellAdditionalExePaths: IPowerShellAdditionalExePathSettings; + powerShellDefaultVersion: string; // This setting is no longer used but is here to assist in cleaning up the users settings. - powerShellExePath: string | undefined; + powerShellExePath: string; promptToUpdatePowerShell: boolean; startAsLoginShell: IStartAsLoginShellSettings; startAutomatically: boolean; @@ -26,7 +26,7 @@ export interface ISettings { sideBar: ISideBarSettings; pester: IPesterSettings; buttons: IButtonSettings; - cwd: string | undefined; + cwd: string; enableReferencesCodeLens: boolean; analyzeOpenDocumentsOnly: boolean; // TODO: Add (deprecated) useX86Host (for testing) @@ -142,10 +142,7 @@ export interface IButtonSettings { showPanelMovementButtons: boolean; } -export function getSettings(): ISettings { - const configuration: vscode.WorkspaceConfiguration = - vscode.workspace.getConfiguration(utils.PowerShellLanguageId); - +export function getDefaultSettings() { const defaultBugReportingSettings: IBugReportingSettings = { project: "https://github.com/PowerShell/vscode-powershell", }; @@ -196,6 +193,10 @@ export function getSettings(): ISettings { useCorrectCasing: false, }; + // We follow the same convention as VS Code - https://github.com/microsoft/vscode/blob/ff00badd955d6cfcb8eab5f25f3edc86b762f49f/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts#L105-L107 + // "Unlike on Linux, ~/.profile is not sourced when logging into a macOS session. This + // is the reason terminals on macOS typically run login shells by default which set up + // the environment. See http://unix.stackexchange.com/a/119675/115410" const defaultStartAsLoginShellSettings: IStartAsLoginShellSettings = { osx: true, linux: false, @@ -225,58 +226,54 @@ export function getSettings(): ISettings { debugOutputVerbosity: "Diagnostic", }; - // TODO: I believe all the defaults can be removed, as the `package.json` - // should supply them (and be the source of truth). However, this proves - // fairly messy to do as it requires casting the configuration to unknown - // and then to `ISettings`. It could work but will take more testing. - return { - startAutomatically: - configuration.get("startAutomatically", true), - powerShellAdditionalExePaths: - configuration.get("powerShellAdditionalExePaths"), - powerShellDefaultVersion: - configuration.get("powerShellDefaultVersion"), - powerShellExePath: - configuration.get("powerShellExePath"), - promptToUpdatePowerShell: - configuration.get("promptToUpdatePowerShell", true), - enableProfileLoading: - configuration.get("enableProfileLoading", true), - helpCompletion: - configuration.get("helpCompletion", CommentType.BlockComment), - scriptAnalysis: - configuration.get("scriptAnalysis", defaultScriptAnalysisSettings), - debugging: - configuration.get("debugging", defaultDebuggingSettings), - developer: - configuration.get("developer", defaultDeveloperSettings), - codeFolding: - configuration.get("codeFolding", defaultCodeFoldingSettings), - codeFormatting: - configuration.get("codeFormatting", defaultCodeFormattingSettings), - integratedConsole: - configuration.get("integratedConsole", defaultIntegratedConsoleSettings), - bugReporting: - configuration.get("bugReporting", defaultBugReportingSettings), - sideBar: - configuration.get("sideBar", defaultSideBarSettings), - pester: - configuration.get("pester", defaultPesterSettings), - buttons: - configuration.get("buttons", defaultButtonSettings), - startAsLoginShell: - // We follow the same convention as VS Code - https://github.com/microsoft/vscode/blob/ff00badd955d6cfcb8eab5f25f3edc86b762f49f/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts#L105-L107 - // "Unlike on Linux, ~/.profile is not sourced when logging into a macOS session. This - // is the reason terminals on macOS typically run login shells by default which set up - // the environment. See http://unix.stackexchange.com/a/119675/115410" - configuration.get("startAsLoginShell", defaultStartAsLoginShellSettings), - cwd: // NOTE: This must be validated at startup via `validateCwdSetting()`. There's probably a better way to do this. - configuration.get("cwd"), - enableReferencesCodeLens: - configuration.get("enableReferencesCodeLens", true), - analyzeOpenDocumentsOnly: - configuration.get("analyzeOpenDocumentsOnly", false), + const defaultSettings: ISettings = { + startAutomatically: true, + powerShellAdditionalExePaths: {}, + powerShellDefaultVersion: "", + powerShellExePath: "", + promptToUpdatePowerShell: true, + enableProfileLoading: true, + helpCompletion: CommentType.BlockComment, + scriptAnalysis: defaultScriptAnalysisSettings, + debugging: defaultDebuggingSettings, + developer: defaultDeveloperSettings, + codeFolding: defaultCodeFoldingSettings, + codeFormatting: defaultCodeFormattingSettings, + integratedConsole: defaultIntegratedConsoleSettings, + bugReporting: defaultBugReportingSettings, + sideBar: defaultSideBarSettings, + pester: defaultPesterSettings, + buttons: defaultButtonSettings, + startAsLoginShell: defaultStartAsLoginShellSettings, + cwd: "", + enableReferencesCodeLens: true, + analyzeOpenDocumentsOnly: false, }; + + return defaultSettings; +} + +// This is a recursive function which unpacks a WorkspaceConfiguration into our settings. +function getSetting(key: string | undefined, value: TSetting, configuration: vscode.WorkspaceConfiguration): TSetting { + // Base case where we're looking at a primitive type (or our special record). + if (key !== undefined && (typeof (value) !== "object" || key === "powerShellAdditionalExePaths")) { + return configuration.get(key, value); + } + + // Otherwise we're looking at one of our interfaces and need to extract. + for (const property in value) { + const subKey = key !== undefined ? `${key}.${property}` : property; + value[property] = getSetting(subKey, value[property], configuration); + } + + return value; +} + +export function getSettings(): ISettings { + const configuration: vscode.WorkspaceConfiguration = + vscode.workspace.getConfiguration(utils.PowerShellLanguageId); + + return getSetting(undefined, getDefaultSettings(), configuration); } // Get the ConfigurationTarget (read: scope) of where the *effective* setting value comes from diff --git a/test/.vscode/settings.json b/test/.vscode/settings.json index 9678952187..b731d24659 100644 --- a/test/.vscode/settings.json +++ b/test/.vscode/settings.json @@ -1,4 +1,7 @@ { "terminal.integrated.shellIntegration.enabled": false, "powershell.enableProfileLoading": false, + "powershell.powerShellAdditionalExePaths": { + "Some PowerShell": "somePath" + }, } diff --git a/test/core/settings.test.ts b/test/core/settings.test.ts index 0ad76f920c..d547b27994 100644 --- a/test/core/settings.test.ts +++ b/test/core/settings.test.ts @@ -3,25 +3,34 @@ import * as assert from "assert"; import * as vscode from "vscode"; -import { CommentType, getSettings, changeSetting, getEffectiveConfigurationTarget } from "../../src/settings"; +import * as settings from "../../src/settings"; describe("Settings module", function () { it("Loads without error", function () { - assert.doesNotThrow(getSettings); + assert.doesNotThrow(settings.getSettings); }); + it("Loads the correct defaults", function () { + const testSettings = settings.getDefaultSettings(); + testSettings.enableProfileLoading = false; + testSettings.powerShellAdditionalExePaths = { "Some PowerShell": "somePath" }; + const actualSettings = settings.getSettings(); + assert.deepStrictEqual(actualSettings, testSettings); + }); + + it("Updates correctly", async function () { - await changeSetting("helpCompletion", CommentType.LineComment, false, undefined); - assert.strictEqual(getSettings().helpCompletion, CommentType.LineComment); + await settings.changeSetting("helpCompletion", settings.CommentType.LineComment, false, undefined); + assert.strictEqual(settings.getSettings().helpCompletion, settings.CommentType.LineComment); }); it("Gets the effective configuration target", async function () { - await changeSetting("helpCompletion", CommentType.LineComment, false, undefined); - let target = getEffectiveConfigurationTarget("helpCompletion"); + await settings.changeSetting("helpCompletion", settings.CommentType.LineComment, false, undefined); + let target = settings.getEffectiveConfigurationTarget("helpCompletion"); assert.strictEqual(target, vscode.ConfigurationTarget.Workspace); - await changeSetting("helpCompletion", undefined, false, undefined); - target = getEffectiveConfigurationTarget("helpCompletion"); + await settings.changeSetting("helpCompletion", undefined, false, undefined); + target = settings.getEffectiveConfigurationTarget("helpCompletion"); assert.strictEqual(target, undefined); }); }); From 942a201e0caae17f4bb0beaa91856e7fbe9cd42a Mon Sep 17 00:00:00 2001 From: Andy Jordan Date: Wed, 2 Nov 2022 16:44:02 -0700 Subject: [PATCH 6/9] Use classes instead of interfaces --- src/features/HelpCompletion.ts | 6 +- src/platform.ts | 6 +- src/process.ts | 2 +- src/session.ts | 6 +- src/settings.ts | 283 +++++++++++---------------------- test/core/settings.test.ts | 2 +- 6 files changed, 101 insertions(+), 204 deletions(-) diff --git a/src/features/HelpCompletion.ts b/src/features/HelpCompletion.ts index 8bbf14d578..e2931dc461 100644 --- a/src/features/HelpCompletion.ts +++ b/src/features/HelpCompletion.ts @@ -7,7 +7,7 @@ import { } from "vscode"; import { RequestType } from "vscode-languageclient"; import { LanguageClient } from "vscode-languageclient/node"; -import { ISettings, CommentType, getSettings } from "../settings"; +import { Settings, CommentType, getSettings } from "../settings"; import { LanguageClientConsumer } from "../languageClientConsumer"; // eslint-disable-next-line @typescript-eslint/no-empty-interface @@ -27,7 +27,7 @@ enum SearchState { Searching, Locked, Found } export class HelpCompletionFeature extends LanguageClientConsumer { private helpCompletionProvider: HelpCompletionProvider | undefined; private disposable: Disposable | undefined; - private settings: ISettings; + private settings: Settings; constructor() { super(); @@ -125,7 +125,7 @@ class HelpCompletionProvider { private lastChangeRange: Range | undefined; private lastDocument: TextDocument | undefined; private langClient: LanguageClient | undefined; - private settings: ISettings; + private settings: Settings; constructor() { this.triggerFinderHelpComment = new TriggerFinder("##"); diff --git a/src/platform.ts b/src/platform.ts index 4225b916d5..1aa2edc682 100644 --- a/src/platform.ts +++ b/src/platform.ts @@ -5,7 +5,7 @@ import * as os from "os"; import * as path from "path"; import * as process from "process"; import { integer } from "vscode-languageserver-protocol"; -import { IPowerShellAdditionalExePathSettings } from "./settings"; +import { PowerShellAdditionalExePathSettings } from "./settings"; // This uses require so we can rewire it in unit tests! // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-var-requires @@ -79,7 +79,7 @@ export class PowerShellExeFinder { private readonly platformDetails: IPlatformDetails; // Additional configured PowerShells - private readonly additionalPSExeSettings: IPowerShellAdditionalExePathSettings; + private readonly additionalPSExeSettings: PowerShellAdditionalExePathSettings; private winPS: IPossiblePowerShellExe | undefined; @@ -92,7 +92,7 @@ export class PowerShellExeFinder { */ constructor( platformDetails?: IPlatformDetails, - additionalPowerShellExes?: IPowerShellAdditionalExePathSettings) { + additionalPowerShellExes?: PowerShellAdditionalExePathSettings) { this.platformDetails = platformDetails ?? getPlatformDetails(); this.additionalPSExeSettings = additionalPowerShellExes ?? {}; diff --git a/src/process.ts b/src/process.ts index c3458cba38..5165f6160d 100644 --- a/src/process.ts +++ b/src/process.ts @@ -31,7 +31,7 @@ export class PowerShellProcess { private logger: Logger, private startPsesArgs: string, private sessionFilePath: vscode.Uri, - private sessionSettings: Settings.ISettings) { + private sessionSettings: Settings.Settings) { this.onExited = this.onExitedEmitter.event; } diff --git a/src/session.ts b/src/session.ts index f27699bbe9..abefa51b7d 100644 --- a/src/session.ts +++ b/src/session.ts @@ -9,7 +9,7 @@ import TelemetryReporter, { TelemetryEventProperties, TelemetryEventMeasurements import { Message } from "vscode-jsonrpc"; import { Logger } from "./logging"; import { PowerShellProcess } from "./process"; -import { ISettings, changeSetting, getSettings, getEffectiveConfigurationTarget, validateCwdSetting } from "./settings"; +import { Settings, changeSetting, getSettings, getEffectiveConfigurationTarget, validateCwdSetting } from "./settings"; import utils = require("./utils"); import { @@ -102,7 +102,7 @@ export class SessionManager implements Middleware { constructor( private extensionContext: vscode.ExtensionContext, - private sessionSettings: ISettings, + private sessionSettings: Settings, private logger: Logger, private documentSelector: DocumentSelector, hostName: string, @@ -234,7 +234,7 @@ export class SessionManager implements Middleware { return vscode.Uri.joinPath(this.sessionsFolder, `PSES-VSCode-${process.env.VSCODE_PID}-${uniqueId}.json`); } - public async createDebugSessionProcess(settings: ISettings): Promise { + public async createDebugSessionProcess(settings: Settings): Promise { // NOTE: We only support one temporary Extension Terminal at a time. To // support more, we need to track each separately, and tie the session // for the event handler to the right process (and dispose of the event diff --git a/src/settings.ts b/src/settings.ts index 1d97bab798..a702c575c0 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -6,29 +6,32 @@ import utils = require("./utils"); import os = require("os"); import { Logger } from "./logging"; -export interface ISettings { - powerShellAdditionalExePaths: IPowerShellAdditionalExePathSettings; - powerShellDefaultVersion: string; +// eslint-disable-next-line @typescript-eslint/no-extraneous-class +class PartialSettings { } + +export class Settings extends PartialSettings { + powerShellAdditionalExePaths: PowerShellAdditionalExePathSettings = {}; + powerShellDefaultVersion = ""; // This setting is no longer used but is here to assist in cleaning up the users settings. - powerShellExePath: string; - promptToUpdatePowerShell: boolean; - startAsLoginShell: IStartAsLoginShellSettings; - startAutomatically: boolean; - enableProfileLoading: boolean; - helpCompletion: string; - scriptAnalysis: IScriptAnalysisSettings; - debugging: IDebuggingSettings; - developer: IDeveloperSettings; - codeFolding: ICodeFoldingSettings; - codeFormatting: ICodeFormattingSettings; - integratedConsole: IIntegratedConsoleSettings; - bugReporting: IBugReportingSettings; - sideBar: ISideBarSettings; - pester: IPesterSettings; - buttons: IButtonSettings; - cwd: string; - enableReferencesCodeLens: boolean; - analyzeOpenDocumentsOnly: boolean; + powerShellExePath = ""; + promptToUpdatePowerShell = true; + startAsLoginShell = new StartAsLoginShellSettings(); + startAutomatically = true; + enableProfileLoading = true; + helpCompletion = CommentType.BlockComment; + scriptAnalysis = new ScriptAnalysisSettings(); + debugging = new DebuggingSettings(); + developer = new DeveloperSettings(); + codeFolding = new CodeFoldingSettings(); + codeFormatting = new CodeFormattingSettings(); + integratedConsole = new IntegratedConsoleSettings(); + bugReporting = new BugReportingSettings(); + sideBar = new SideBarSettings(); + pester = new PesterSettings(); + buttons = new ButtonSettings(); + cwd = ""; + enableReferencesCodeLens = true; + analyzeOpenDocumentsOnly = false; // TODO: Add (deprecated) useX86Host (for testing) } @@ -61,202 +64,96 @@ export enum CommentType { LineComment = "LineComment", } -export type IPowerShellAdditionalExePathSettings = Record; +export type PowerShellAdditionalExePathSettings = Record; -export interface IBugReportingSettings { - project: string; +class BugReportingSettings extends PartialSettings { + project = "https://github.com/PowerShell/vscode-powershell"; } -export interface ICodeFoldingSettings { - enable: boolean; - showLastLine: boolean; +class CodeFoldingSettings extends PartialSettings { + enable = true; + showLastLine = true; } -export interface ICodeFormattingSettings { - autoCorrectAliases: boolean; - avoidSemicolonsAsLineTerminators: boolean; - preset: CodeFormattingPreset; - openBraceOnSameLine: boolean; - newLineAfterOpenBrace: boolean; - newLineAfterCloseBrace: boolean; - pipelineIndentationStyle: PipelineIndentationStyle; - whitespaceBeforeOpenBrace: boolean; - whitespaceBeforeOpenParen: boolean; - whitespaceAroundOperator: boolean; - whitespaceAfterSeparator: boolean; - whitespaceBetweenParameters: boolean; - whitespaceInsideBrace: boolean; - addWhitespaceAroundPipe: boolean; - trimWhitespaceAroundPipe: boolean; - ignoreOneLineBlock: boolean; - alignPropertyValuePairs: boolean; - useConstantStrings: boolean; - useCorrectCasing: boolean; +class CodeFormattingSettings extends PartialSettings { + autoCorrectAliases = false; + avoidSemicolonsAsLineTerminators = false; + preset = CodeFormattingPreset.Custom; + openBraceOnSameLine = true; + newLineAfterOpenBrace = true; + newLineAfterCloseBrace = true; + pipelineIndentationStyle = PipelineIndentationStyle.NoIndentation; + whitespaceBeforeOpenBrace = true; + whitespaceBeforeOpenParen = true; + whitespaceAroundOperator = true; + whitespaceAfterSeparator = true; + whitespaceBetweenParameters = false; + whitespaceInsideBrace = true; + addWhitespaceAroundPipe = true; + trimWhitespaceAroundPipe = false; + ignoreOneLineBlock = true; + alignPropertyValuePairs = true; + useConstantStrings = false; + useCorrectCasing = false; } -export interface IScriptAnalysisSettings { - enable: boolean; - settingsPath: string; +class ScriptAnalysisSettings extends PartialSettings { + enable = true; + settingsPath = "PSScriptAnalyzerSettings.psd1"; } -export interface IDebuggingSettings { - createTemporaryIntegratedConsole: boolean; +class DebuggingSettings extends PartialSettings { + createTemporaryIntegratedConsole = false; } -export interface IDeveloperSettings { - featureFlags: string[]; - bundledModulesPath: string; - editorServicesLogLevel: LogLevel; - editorServicesWaitForDebugger: boolean; - waitForSessionFileTimeoutSeconds: number; +class DeveloperSettings extends PartialSettings { + featureFlags = []; + // From `/out/main.js` we go to the directory before and + // then into the other repo. + bundledModulesPath = "../../PowerShellEditorServices/module"; + editorServicesLogLevel = LogLevel.Normal; + editorServicesWaitForDebugger = false; + waitForSessionFileTimeoutSeconds = 240; } -export interface IStartAsLoginShellSettings { - osx: boolean; - linux: boolean; +// We follow the same convention as VS Code - https://github.com/microsoft/vscode/blob/ff00badd955d6cfcb8eab5f25f3edc86b762f49f/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts#L105-L107 +// "Unlike on Linux, ~/.profile is not sourced when logging into a macOS session. This +// is the reason terminals on macOS typically run login shells by default which set up +// the environment. See http://unix.stackexchange.com/a/119675/115410" +class StartAsLoginShellSettings extends PartialSettings { + osx = true; + linux = false; } -export interface IIntegratedConsoleSettings { - showOnStartup: boolean; - startInBackground: boolean; - focusConsoleOnExecute: boolean; - useLegacyReadLine: boolean; - forceClearScrollbackBuffer: boolean; - suppressStartupBanner: boolean; +class IntegratedConsoleSettings extends PartialSettings { + showOnStartup = true; + startInBackground = false; + focusConsoleOnExecute = true; + useLegacyReadLine = false; + forceClearScrollbackBuffer = false; + suppressStartupBanner = false; } -export interface ISideBarSettings { +class SideBarSettings extends PartialSettings { // TODO: add CommandExplorerExcludeFilter - CommandExplorerVisibility: boolean; -} - -export interface IPesterSettings { - // TODO: add codeLens property - useLegacyCodeLens: boolean; - outputVerbosity: string; - debugOutputVerbosity: string; + CommandExplorerVisibility = true; } -export interface IButtonSettings { - showRunButtons: boolean; - showPanelMovementButtons: boolean; +class PesterSettings extends PartialSettings { + useLegacyCodeLens = true; + outputVerbosity = "FromPreference"; + debugOutputVerbosity = "Diagnostic"; } -export function getDefaultSettings() { - const defaultBugReportingSettings: IBugReportingSettings = { - project: "https://github.com/PowerShell/vscode-powershell", - }; - - const defaultScriptAnalysisSettings: IScriptAnalysisSettings = { - enable: true, - settingsPath: "PSScriptAnalyzerSettings.psd1", - }; - - const defaultDebuggingSettings: IDebuggingSettings = { - createTemporaryIntegratedConsole: false, - }; - - const defaultDeveloperSettings: IDeveloperSettings = { - featureFlags: [], - // From `/out/main.js` we go to the directory before and - // then into the other repo. - bundledModulesPath: "../../PowerShellEditorServices/module", - editorServicesLogLevel: LogLevel.Normal, - editorServicesWaitForDebugger: false, - waitForSessionFileTimeoutSeconds: 240, - }; - - const defaultCodeFoldingSettings: ICodeFoldingSettings = { - enable: true, - showLastLine: true, - }; - - const defaultCodeFormattingSettings: ICodeFormattingSettings = { - autoCorrectAliases: false, - avoidSemicolonsAsLineTerminators: false, - preset: CodeFormattingPreset.Custom, - openBraceOnSameLine: true, - newLineAfterOpenBrace: true, - newLineAfterCloseBrace: true, - pipelineIndentationStyle: PipelineIndentationStyle.NoIndentation, - whitespaceBeforeOpenBrace: true, - whitespaceBeforeOpenParen: true, - whitespaceAroundOperator: true, - whitespaceAfterSeparator: true, - whitespaceBetweenParameters: false, - whitespaceInsideBrace: true, - addWhitespaceAroundPipe: true, - trimWhitespaceAroundPipe: false, - ignoreOneLineBlock: true, - alignPropertyValuePairs: true, - useConstantStrings: false, - useCorrectCasing: false, - }; - - // We follow the same convention as VS Code - https://github.com/microsoft/vscode/blob/ff00badd955d6cfcb8eab5f25f3edc86b762f49f/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts#L105-L107 - // "Unlike on Linux, ~/.profile is not sourced when logging into a macOS session. This - // is the reason terminals on macOS typically run login shells by default which set up - // the environment. See http://unix.stackexchange.com/a/119675/115410" - const defaultStartAsLoginShellSettings: IStartAsLoginShellSettings = { - osx: true, - linux: false, - }; - - const defaultIntegratedConsoleSettings: IIntegratedConsoleSettings = { - showOnStartup: true, - startInBackground: false, - focusConsoleOnExecute: true, - useLegacyReadLine: false, - forceClearScrollbackBuffer: false, - suppressStartupBanner: false, - }; - - const defaultSideBarSettings: ISideBarSettings = { - CommandExplorerVisibility: true, - }; - - const defaultButtonSettings: IButtonSettings = { - showRunButtons: true, - showPanelMovementButtons: false - }; - - const defaultPesterSettings: IPesterSettings = { - useLegacyCodeLens: true, - outputVerbosity: "FromPreference", - debugOutputVerbosity: "Diagnostic", - }; - - const defaultSettings: ISettings = { - startAutomatically: true, - powerShellAdditionalExePaths: {}, - powerShellDefaultVersion: "", - powerShellExePath: "", - promptToUpdatePowerShell: true, - enableProfileLoading: true, - helpCompletion: CommentType.BlockComment, - scriptAnalysis: defaultScriptAnalysisSettings, - debugging: defaultDebuggingSettings, - developer: defaultDeveloperSettings, - codeFolding: defaultCodeFoldingSettings, - codeFormatting: defaultCodeFormattingSettings, - integratedConsole: defaultIntegratedConsoleSettings, - bugReporting: defaultBugReportingSettings, - sideBar: defaultSideBarSettings, - pester: defaultPesterSettings, - buttons: defaultButtonSettings, - startAsLoginShell: defaultStartAsLoginShellSettings, - cwd: "", - enableReferencesCodeLens: true, - analyzeOpenDocumentsOnly: false, - }; - - return defaultSettings; +class ButtonSettings extends PartialSettings { + showRunButtons = true; + showPanelMovementButtons = false; } // This is a recursive function which unpacks a WorkspaceConfiguration into our settings. function getSetting(key: string | undefined, value: TSetting, configuration: vscode.WorkspaceConfiguration): TSetting { // Base case where we're looking at a primitive type (or our special record). - if (key !== undefined && (typeof (value) !== "object" || key === "powerShellAdditionalExePaths")) { + if (key !== undefined && !(value instanceof PartialSettings)) { return configuration.get(key, value); } @@ -269,11 +166,11 @@ function getSetting(key: string | undefined, value: TSetting, configur return value; } -export function getSettings(): ISettings { +export function getSettings(): Settings { const configuration: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration(utils.PowerShellLanguageId); - return getSetting(undefined, getDefaultSettings(), configuration); + return getSetting(undefined, new Settings(), configuration); } // Get the ConfigurationTarget (read: scope) of where the *effective* setting value comes from diff --git a/test/core/settings.test.ts b/test/core/settings.test.ts index d547b27994..00b1c5d5ee 100644 --- a/test/core/settings.test.ts +++ b/test/core/settings.test.ts @@ -11,7 +11,7 @@ describe("Settings module", function () { }); it("Loads the correct defaults", function () { - const testSettings = settings.getDefaultSettings(); + const testSettings = new settings.Settings(); testSettings.enableProfileLoading = false; testSettings.powerShellAdditionalExePaths = { "Some PowerShell": "somePath" }; const actualSettings = settings.getSettings(); From 845b30cd5c7242ba392343726dcd613e8eccb09a Mon Sep 17 00:00:00 2001 From: Andy Jordan Date: Thu, 3 Nov 2022 09:55:42 -0700 Subject: [PATCH 7/9] Deprecate `bugReporting.project` setting This setting was never meant to be changed! --- package.json | 3 ++- src/features/GenerateBugReport.ts | 3 +-- src/session.ts | 2 ++ src/settings.ts | 5 ----- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 5cdb477f26..0654eeb635 100644 --- a/package.json +++ b/package.json @@ -641,7 +641,8 @@ "powershell.bugReporting.project": { "type": "string", "default": "https://github.com/PowerShell/vscode-powershell", - "description": "Specifies the URL of the GitHub project in which to generate bug reports." + "description": "Specifies the URL of the GitHub project in which to generate bug reports.", + "deprecationMessage": "This setting was never meant to be changed!" }, "powershell.helpCompletion": { "type": "string", diff --git a/src/features/GenerateBugReport.ts b/src/features/GenerateBugReport.ts index f1a50751f7..5d0049428c 100644 --- a/src/features/GenerateBugReport.ts +++ b/src/features/GenerateBugReport.ts @@ -5,11 +5,10 @@ import os = require("os"); import vscode = require("vscode"); import child_process = require("child_process"); import { SessionManager } from "../session"; -import { getSettings } from "../settings"; const queryStringPrefix = "?"; -const project = getSettings().bugReporting.project; +const project = "https://github.com/PowerShell/vscode-powershell"; const issuesUrl = `${project}/issues/new`; const extensions = diff --git a/src/session.ts b/src/session.ts index abefa51b7d..4f706826db 100644 --- a/src/session.ts +++ b/src/session.ts @@ -625,6 +625,7 @@ Type 'help' to get help. const clientOptions: LanguageClientOptions = { documentSelector: this.documentSelector, synchronize: { + // TODO: This is deprecated and they should be pulled by the server. // backend uses "files" and "search" to ignore references. configurationSection: [utils.PowerShellLanguageId, "files", "search"], // TODO: fileEvents: vscode.workspace.createFileSystemWatcher('**/.eslintrc') @@ -657,6 +658,7 @@ Type 'help' to get help. this.languageClient = new LanguageClient("PowerShell Editor Services", connectFunc, clientOptions); // This enables handling Semantic Highlighting messages in PowerShell Editor Services + // TODO: We should only turn this on in preview. this.languageClient.registerProposedFeatures(); this.languageClient.onTelemetry((event) => { diff --git a/src/settings.ts b/src/settings.ts index a702c575c0..06c4048766 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -25,7 +25,6 @@ export class Settings extends PartialSettings { codeFolding = new CodeFoldingSettings(); codeFormatting = new CodeFormattingSettings(); integratedConsole = new IntegratedConsoleSettings(); - bugReporting = new BugReportingSettings(); sideBar = new SideBarSettings(); pester = new PesterSettings(); buttons = new ButtonSettings(); @@ -66,10 +65,6 @@ export enum CommentType { export type PowerShellAdditionalExePathSettings = Record; -class BugReportingSettings extends PartialSettings { - project = "https://github.com/PowerShell/vscode-powershell"; -} - class CodeFoldingSettings extends PartialSettings { enable = true; showLastLine = true; From 1cafa171b41642c5ffd171f104ff85bbbea64418 Mon Sep 17 00:00:00 2001 From: Andy Jordan Date: Thu, 3 Nov 2022 10:02:28 -0700 Subject: [PATCH 8/9] Add `CommandExplorerExcludeFilter` to `Settings` class --- src/features/GetCommands.ts | 5 +++-- src/settings.ts | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/features/GetCommands.ts b/src/features/GetCommands.ts index 7756df75b9..c33acd85a8 100644 --- a/src/features/GetCommands.ts +++ b/src/features/GetCommands.ts @@ -6,6 +6,7 @@ import { RequestType0 } from "vscode-languageclient"; import { LanguageClient } from "vscode-languageclient/node"; import { Logger } from "../logging"; import { LanguageClientConsumer } from "../languageClientConsumer"; +import { getSettings } from "../settings"; interface ICommand { name: string; @@ -68,8 +69,8 @@ export class GetCommandsFeature extends LanguageClientConsumer { return; } await this.languageClient.sendRequest(GetCommandRequestType).then((result) => { - const SidebarConfig = vscode.workspace.getConfiguration("powershell.sideBar"); - const excludeFilter = (SidebarConfig.CommandExplorerExcludeFilter).map((filter: string) => filter.toLowerCase()); + const exclusions = getSettings().sideBar.CommandExplorerExcludeFilter; + const excludeFilter = exclusions.map((filter: string) => filter.toLowerCase()); result = result.filter((command) => (excludeFilter.indexOf(command.moduleName.toLowerCase()) === -1)); this.commandsExplorerProvider.powerShellCommands = result.map(toCommand); this.commandsExplorerProvider.refresh(); diff --git a/src/settings.ts b/src/settings.ts index 06c4048766..214e8931ed 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -102,7 +102,7 @@ class DebuggingSettings extends PartialSettings { } class DeveloperSettings extends PartialSettings { - featureFlags = []; + featureFlags: string[] = []; // From `/out/main.js` we go to the directory before and // then into the other repo. bundledModulesPath = "../../PowerShellEditorServices/module"; @@ -130,8 +130,8 @@ class IntegratedConsoleSettings extends PartialSettings { } class SideBarSettings extends PartialSettings { - // TODO: add CommandExplorerExcludeFilter CommandExplorerVisibility = true; + CommandExplorerExcludeFilter: string[] = []; } class PesterSettings extends PartialSettings { From 1046278ee04f1743f40156ecc6452e974e485cea Mon Sep 17 00:00:00 2001 From: Andy Jordan Date: Thu, 3 Nov 2022 10:10:51 -0700 Subject: [PATCH 9/9] Remove `CodeFoldingSettings` class As the client-side folder was removed eons ago. --- src/settings.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/settings.ts b/src/settings.ts index 214e8931ed..9380baa4ce 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -6,6 +6,14 @@ import utils = require("./utils"); import os = require("os"); import { Logger } from "./logging"; +// TODO: Quite a few of these settings are unused in the client and instead +// exist just for the server. Those settings do not need to be represented in +// this class, as the LSP layers take care of communicating them. Frankly, this +// class is over-engineered and seems to have originally been created to avoid +// using vscode.workspace.getConfiguration() directly. It wasn't a bad idea to +// keep things organized so consistent...but it ended up failing in execution. +// Perhaps we just get rid of this entirely? + // eslint-disable-next-line @typescript-eslint/no-extraneous-class class PartialSettings { } @@ -22,7 +30,6 @@ export class Settings extends PartialSettings { scriptAnalysis = new ScriptAnalysisSettings(); debugging = new DebuggingSettings(); developer = new DeveloperSettings(); - codeFolding = new CodeFoldingSettings(); codeFormatting = new CodeFormattingSettings(); integratedConsole = new IntegratedConsoleSettings(); sideBar = new SideBarSettings(); @@ -65,11 +72,6 @@ export enum CommentType { export type PowerShellAdditionalExePathSettings = Record; -class CodeFoldingSettings extends PartialSettings { - enable = true; - showLastLine = true; -} - class CodeFormattingSettings extends PartialSettings { autoCorrectAliases = false; avoidSemicolonsAsLineTerminators = false;