Skip to content

Commit c907d1c

Browse files
committed
Automatically fill in ISettings from configuration
Using recursion! With a test!
1 parent 99dee72 commit c907d1c

File tree

3 files changed

+73
-64
lines changed

3 files changed

+73
-64
lines changed

src/settings.ts

+53-56
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import os = require("os");
77
import { Logger } from "./logging";
88

99
export interface ISettings {
10-
powerShellAdditionalExePaths: IPowerShellAdditionalExePathSettings | undefined;
10+
powerShellAdditionalExePaths: IPowerShellAdditionalExePathSettings;
1111
powerShellDefaultVersion: string | undefined;
1212
// This setting is no longer used but is here to assist in cleaning up the users settings.
1313
powerShellExePath: string | undefined;
@@ -142,10 +142,7 @@ export interface IButtonSettings {
142142
showPanelMovementButtons: boolean;
143143
}
144144

145-
export function getSettings(): ISettings {
146-
const configuration: vscode.WorkspaceConfiguration =
147-
vscode.workspace.getConfiguration(utils.PowerShellLanguageId);
148-
145+
export function getDefaultSettings() {
149146
const defaultBugReportingSettings: IBugReportingSettings = {
150147
project: "https://github.com/PowerShell/vscode-powershell",
151148
};
@@ -196,6 +193,10 @@ export function getSettings(): ISettings {
196193
useCorrectCasing: false,
197194
};
198195

196+
// 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
197+
// "Unlike on Linux, ~/.profile is not sourced when logging into a macOS session. This
198+
// is the reason terminals on macOS typically run login shells by default which set up
199+
// the environment. See http://unix.stackexchange.com/a/119675/115410"
199200
const defaultStartAsLoginShellSettings: IStartAsLoginShellSettings = {
200201
osx: true,
201202
linux: false,
@@ -225,58 +226,54 @@ export function getSettings(): ISettings {
225226
debugOutputVerbosity: "Diagnostic",
226227
};
227228

228-
// TODO: I believe all the defaults can be removed, as the `package.json`
229-
// should supply them (and be the source of truth). However, this proves
230-
// fairly messy to do as it requires casting the configuration to unknown
231-
// and then to `ISettings`. It could work but will take more testing.
232-
return {
233-
startAutomatically:
234-
configuration.get<boolean>("startAutomatically", true),
235-
powerShellAdditionalExePaths:
236-
configuration.get<IPowerShellAdditionalExePathSettings>("powerShellAdditionalExePaths"),
237-
powerShellDefaultVersion:
238-
configuration.get<string>("powerShellDefaultVersion"),
239-
powerShellExePath:
240-
configuration.get<string>("powerShellExePath"),
241-
promptToUpdatePowerShell:
242-
configuration.get<boolean>("promptToUpdatePowerShell", true),
243-
enableProfileLoading:
244-
configuration.get<boolean>("enableProfileLoading", true),
245-
helpCompletion:
246-
configuration.get<string>("helpCompletion", CommentType.BlockComment),
247-
scriptAnalysis:
248-
configuration.get<IScriptAnalysisSettings>("scriptAnalysis", defaultScriptAnalysisSettings),
249-
debugging:
250-
configuration.get<IDebuggingSettings>("debugging", defaultDebuggingSettings),
251-
developer:
252-
configuration.get<IDeveloperSettings>("developer", defaultDeveloperSettings),
253-
codeFolding:
254-
configuration.get<ICodeFoldingSettings>("codeFolding", defaultCodeFoldingSettings),
255-
codeFormatting:
256-
configuration.get<ICodeFormattingSettings>("codeFormatting", defaultCodeFormattingSettings),
257-
integratedConsole:
258-
configuration.get<IIntegratedConsoleSettings>("integratedConsole", defaultIntegratedConsoleSettings),
259-
bugReporting:
260-
configuration.get<IBugReportingSettings>("bugReporting", defaultBugReportingSettings),
261-
sideBar:
262-
configuration.get<ISideBarSettings>("sideBar", defaultSideBarSettings),
263-
pester:
264-
configuration.get<IPesterSettings>("pester", defaultPesterSettings),
265-
buttons:
266-
configuration.get<IButtonSettings>("buttons", defaultButtonSettings),
267-
startAsLoginShell:
268-
// 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
269-
// "Unlike on Linux, ~/.profile is not sourced when logging into a macOS session. This
270-
// is the reason terminals on macOS typically run login shells by default which set up
271-
// the environment. See http://unix.stackexchange.com/a/119675/115410"
272-
configuration.get<IStartAsLoginShellSettings>("startAsLoginShell", defaultStartAsLoginShellSettings),
273-
cwd: // NOTE: This must be validated at startup via `validateCwdSetting()`. There's probably a better way to do this.
274-
configuration.get<string>("cwd"),
275-
enableReferencesCodeLens:
276-
configuration.get<boolean>("enableReferencesCodeLens", true),
277-
analyzeOpenDocumentsOnly:
278-
configuration.get<boolean>("analyzeOpenDocumentsOnly", false),
229+
const defaultSettings: ISettings = {
230+
startAutomatically: true,
231+
powerShellAdditionalExePaths: {},
232+
powerShellDefaultVersion: "",
233+
powerShellExePath: "",
234+
promptToUpdatePowerShell: true,
235+
enableProfileLoading: true,
236+
helpCompletion: CommentType.BlockComment,
237+
scriptAnalysis: defaultScriptAnalysisSettings,
238+
debugging: defaultDebuggingSettings,
239+
developer: defaultDeveloperSettings,
240+
codeFolding: defaultCodeFoldingSettings,
241+
codeFormatting: defaultCodeFormattingSettings,
242+
integratedConsole: defaultIntegratedConsoleSettings,
243+
bugReporting: defaultBugReportingSettings,
244+
sideBar: defaultSideBarSettings,
245+
pester: defaultPesterSettings,
246+
buttons: defaultButtonSettings,
247+
startAsLoginShell: defaultStartAsLoginShellSettings,
248+
cwd: "",
249+
enableReferencesCodeLens: true,
250+
analyzeOpenDocumentsOnly: false,
279251
};
252+
253+
return defaultSettings;
254+
}
255+
256+
// This is a recursive function which unpacks a WorkspaceConfiguration into our settings.
257+
function getSetting<TSetting>(key: string | undefined, value: TSetting, configuration: vscode.WorkspaceConfiguration): TSetting {
258+
// Base case where we're looking at a primitive type (or our special record).
259+
if (key !== undefined && (typeof (value) !== "object" || key === "powerShellAdditionalExePaths")) {
260+
return configuration.get<TSetting>(key, value);
261+
}
262+
263+
// Otherwise we're looking at one of our interfaces and need to extract.
264+
for (const property in value) {
265+
const subKey = key !== undefined ? `${key}.${property}` : property;
266+
value[property] = getSetting(subKey, value[property], configuration);
267+
}
268+
269+
return value;
270+
}
271+
272+
export function getSettings(): ISettings {
273+
const configuration: vscode.WorkspaceConfiguration =
274+
vscode.workspace.getConfiguration(utils.PowerShellLanguageId);
275+
276+
return getSetting(undefined, getDefaultSettings(), configuration);
280277
}
281278

282279
// Get the ConfigurationTarget (read: scope) of where the *effective* setting value comes from

test/.vscode/settings.json

+3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
{
22
"terminal.integrated.shellIntegration.enabled": false,
33
"powershell.enableProfileLoading": false,
4+
"powershell.powerShellAdditionalExePaths": {
5+
"Some PowerShell": "somePath"
6+
},
47
}

test/core/settings.test.ts

+17-8
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,34 @@
33

44
import * as assert from "assert";
55
import * as vscode from "vscode";
6-
import { CommentType, getSettings, changeSetting, getEffectiveConfigurationTarget } from "../../src/settings";
6+
import * as settings from "../../src/settings";
77

88
describe("Settings module", function () {
99
it("Loads without error", function () {
10-
assert.doesNotThrow(getSettings);
10+
assert.doesNotThrow(settings.getSettings);
1111
});
1212

13+
it("Loads the correct defaults", function () {
14+
const testSettings = settings.getDefaultSettings();
15+
testSettings.enableProfileLoading = false;
16+
testSettings.powerShellAdditionalExePaths = { "Some PowerShell": "somePath" };
17+
const actualSettings = settings.getSettings();
18+
assert.deepStrictEqual(actualSettings, testSettings);
19+
});
20+
21+
1322
it("Updates correctly", async function () {
14-
await changeSetting("helpCompletion", CommentType.LineComment, false, undefined);
15-
assert.strictEqual(getSettings().helpCompletion, CommentType.LineComment);
23+
await settings.changeSetting("helpCompletion", settings.CommentType.LineComment, false, undefined);
24+
assert.strictEqual(settings.getSettings().helpCompletion, settings.CommentType.LineComment);
1625
});
1726

1827
it("Gets the effective configuration target", async function () {
19-
await changeSetting("helpCompletion", CommentType.LineComment, false, undefined);
20-
let target = getEffectiveConfigurationTarget("helpCompletion");
28+
await settings.changeSetting("helpCompletion", settings.CommentType.LineComment, false, undefined);
29+
let target = settings.getEffectiveConfigurationTarget("helpCompletion");
2130
assert.strictEqual(target, vscode.ConfigurationTarget.Workspace);
2231

23-
await changeSetting("helpCompletion", undefined, false, undefined);
24-
target = getEffectiveConfigurationTarget("helpCompletion");
32+
await settings.changeSetting("helpCompletion", undefined, false, undefined);
33+
target = settings.getEffectiveConfigurationTarget("helpCompletion");
2534
assert.strictEqual(target, undefined);
2635
});
2736
});

0 commit comments

Comments
 (0)