diff --git a/Extension/c_cpp_properties.schema.json b/Extension/c_cpp_properties.schema.json index 7e9c6d196b..723c107ee4 100644 --- a/Extension/c_cpp_properties.schema.json +++ b/Extension/c_cpp_properties.schema.json @@ -142,6 +142,16 @@ } }, "additionalProperties": false + }, + "customConfigurationVariables": { + "type": "object", + "description": "Custom variables that can be queried through the command ${cpptools:activeConfigCustomVariable} to use for the input variables in launch.json.", + "patternProperties": { + "(^.+$)": { + "type": "string" + } + }, + "additionalProperties": false } }, "additionalProperties": false diff --git a/Extension/package.json b/Extension/package.json index 619f0ae823..d28b558a43 100644 --- a/Extension/package.json +++ b/Extension/package.json @@ -470,6 +470,20 @@ "description": "%c_cpp.configuration.default.systemIncludePath.description%", "scope": "machine-overridable" }, + "C_Cpp.default.customConfigurationVariables": { + "type": [ + "object", + "null" + ], + "default": null, + "patternProperties": { + "(^.+$)": { + "type": "string" + } + }, + "description": "%c_cpp.configuration.default.customConfigurationVariables.description%", + "scope": "machine-overridable" + }, "C_Cpp.default.enableConfigurationSquiggles": { "type": "boolean", "default": true, diff --git a/Extension/package.nls.json b/Extension/package.nls.json index d7b17c9a74..3f6a546f1d 100644 --- a/Extension/package.nls.json +++ b/Extension/package.nls.json @@ -60,6 +60,7 @@ "c_cpp.configuration.default.browse.limitSymbolsToIncludedHeaders.description": "The value to use in a configuration if \"browse.limitSymbolsToIncludedHeaders\" is either not specified or set to \"${default}\".", "c_cpp.configuration.default.systemIncludePath.description": "The value to use for the system include path. If set, it overrides the system include path acquired via \"compilerPath\" and \"compileCommands\" settings.", "c_cpp.configuration.default.enableConfigurationSquiggles.description": "Controls whether the extension will report errors detected in c_cpp_properties.json.", + "c_cpp.configuration.default.customConfigurationVariables.description": "The value to use in a configuration if \"customConfigurationVariables\" is not set, or the values to insert if \"${default}\" is present as a key in \"customConfigurationVariables\".", "c_cpp.configuration.updateChannel.description": "Set to \"Insiders\" to automatically download and install the latest Insiders builds of the extension, which include upcoming features and bug fixes.", "c_cpp.configuration.experimentalFeatures.description": "Controls whether \"experimental\" features are usable.", "c_cpp.configuration.suggestSnippets.description": "If true, snippets are provided by the language server.", diff --git a/Extension/src/LanguageServer/client.ts b/Extension/src/LanguageServer/client.ts index 4a6acacb55..bf21d5cf66 100644 --- a/Extension/src/LanguageServer/client.ts +++ b/Extension/src/LanguageServer/client.ts @@ -500,6 +500,7 @@ export interface Client { toggleReferenceResultsView(): void; setCurrentConfigName(configurationName: string): Thenable; getCurrentConfigName(): Thenable; + getCurrentConfigCustomVariable(variableName: string): Thenable; getVcpkgInstalled(): Thenable; getVcpkgEnabled(): Thenable; getCurrentCompilerPathAndArgs(): Thenable; @@ -1778,6 +1779,10 @@ export class DefaultClient implements Client { return this.queueTask(() => Promise.resolve(this.configuration.CurrentConfiguration?.name)); } + public getCurrentConfigCustomVariable(variableName: string): Thenable { + return this.queueTask(() => Promise.resolve(this.configuration.CurrentConfiguration?.customConfigurationVariables?.[variableName] || '')); + } + public setCurrentConfigName(configurationName: string): Thenable { return this.queueTask(() => new Promise((resolve, reject) => { let configurations: configs.Configuration[] = this.configuration.Configurations || []; @@ -2658,6 +2663,7 @@ class NullClient implements Client { toggleReferenceResultsView(): void {} setCurrentConfigName(configurationName: string): Thenable { return Promise.resolve(); } getCurrentConfigName(): Thenable { return Promise.resolve(""); } + getCurrentConfigCustomVariable(variableName: string): Thenable { return Promise.resolve(""); } getVcpkgInstalled(): Thenable { return Promise.resolve(false); } getVcpkgEnabled(): Thenable { return Promise.resolve(false); } getCurrentCompilerPathAndArgs(): Thenable { return Promise.resolve(undefined); } diff --git a/Extension/src/LanguageServer/configurations.ts b/Extension/src/LanguageServer/configurations.ts index bb4460026a..06f805ea02 100644 --- a/Extension/src/LanguageServer/configurations.ts +++ b/Extension/src/LanguageServer/configurations.ts @@ -67,6 +67,7 @@ export interface Configuration { forcedInclude?: string[]; configurationProvider?: string; browse?: Browse; + customConfigurationVariables?: {[key: string]: string}; } export interface ConfigurationErrors { @@ -123,6 +124,7 @@ export class CppProperties { private vcpkgIncludes: string[] = []; private vcpkgPathReady: boolean = false; private defaultIntelliSenseMode?: string; + private defaultCustomConfigurationVariables?: { [key: string]: string }; private readonly configurationGlobPattern: string = "c_cpp_properties.json"; private disposables: vscode.Disposable[] = []; private configurationsChanged = new vscode.EventEmitter(); @@ -328,6 +330,9 @@ export class CppProperties { if (isUnset(settings.defaultIntelliSenseMode) || settings.defaultIntelliSenseMode === "") { configuration.intelliSenseMode = this.defaultIntelliSenseMode; } + if (isUnset(settings.defaultCustomConfigurationVariables) || settings.defaultCustomConfigurationVariables === {}) { + configuration.customConfigurationVariables = this.defaultCustomConfigurationVariables; + } } private get ExtendedEnvironment(): Environment { @@ -527,6 +532,25 @@ export class CppProperties { return result; } + private resolveDefaultsDictionary(entries: { [key: string] : string }, defaultValue: { [key: string] : string } | undefined, env: Environment): { [key: string] : string } { + let result: { [key: string] : string } = {}; + for (const property in entries) { + if (property === "${default}") { + if (defaultValue) { + for (const defaultProperty in defaultValue) { + if (!(defaultProperty in entries)) + { + result[defaultProperty] = util.resolveVariables(defaultValue[defaultProperty], env); + } + } + } + } else { + result[property] = util.resolveVariables(entries[property], env); + } + } + return result; + } + private resolveAndSplit(paths: string[] | undefined, defaultValue: string[] | undefined, env: Environment): string[] { let result: string[] = []; if (paths) { @@ -572,6 +596,16 @@ export class CppProperties { return util.resolveVariables(property, env); } + private updateConfigurationStringDictionary(property: { [key: string]: string } | undefined, defaultValue: { [key: string]: string } | undefined, env: Environment): { [key: string]: string } | undefined { + if (!property || property === {}) { + property = defaultValue; + } + if (!property || property === {}) { + return undefined; + } + return this.resolveDefaultsDictionary(property, defaultValue, env); + } + private updateServerOnFolderSettingsChange(): void { if (!this.configurationJson) { return; @@ -592,6 +626,7 @@ export class CppProperties { configuration.cStandard = this.updateConfigurationString(configuration.cStandard, settings.defaultCStandard, env); configuration.cppStandard = this.updateConfigurationString(configuration.cppStandard, settings.defaultCppStandard, env); configuration.intelliSenseMode = this.updateConfigurationString(configuration.intelliSenseMode, settings.defaultIntelliSenseMode, env); + configuration.customConfigurationVariables = this.updateConfigurationStringDictionary(configuration.customConfigurationVariables, settings.defaultCustomConfigurationVariables, env); configuration.configurationProvider = this.updateConfigurationString(configuration.configurationProvider, settings.defaultConfigurationProvider, env); if (!configuration.browse) { diff --git a/Extension/src/LanguageServer/extension.ts b/Extension/src/LanguageServer/extension.ts index a273222b7f..2e06d811e5 100644 --- a/Extension/src/LanguageServer/extension.ts +++ b/Extension/src/LanguageServer/extension.ts @@ -905,6 +905,7 @@ export function registerCommands(): void { disposables.push(vscode.commands.registerCommand('C_Cpp.VcpkgClipboardInstallSuggested', onVcpkgClipboardInstallSuggested)); disposables.push(vscode.commands.registerCommand('C_Cpp.VcpkgOnlineHelpSuggested', onVcpkgOnlineHelpSuggested)); disposables.push(vscode.commands.registerCommand('cpptools.activeConfigName', onGetActiveConfigName)); + disposables.push(vscode.commands.registerCommand('cpptools.activeConfigCustomVariable', onGetActiveConfigCustomVariable)); disposables.push(vscode.commands.registerCommand('cpptools.setActiveConfigName', onSetActiveConfigName)); getTemporaryCommandRegistrarInstance().executeDelayedCommands(); } @@ -1167,6 +1168,10 @@ function onGetActiveConfigName(): Thenable { return clients.ActiveClient.getCurrentConfigName(); } +function onGetActiveConfigCustomVariable(variableName: string): Thenable { + return clients.ActiveClient.getCurrentConfigCustomVariable(variableName); +} + function onLogDiagnostics(): void { onActivationEvent(); clients.ActiveClient.logDiagnostics(); diff --git a/Extension/src/LanguageServer/settings.ts b/Extension/src/LanguageServer/settings.ts index 5889b6f8ba..a73b192908 100644 --- a/Extension/src/LanguageServer/settings.ts +++ b/Extension/src/LanguageServer/settings.ts @@ -155,6 +155,7 @@ export class CppSettings extends Settings { public get defaultLimitSymbolsToIncludedHeaders(): boolean | undefined { return super.Section.get("default.browse.limitSymbolsToIncludedHeaders"); } public get defaultSystemIncludePath(): string[] | undefined { return super.Section.get("default.systemIncludePath"); } public get defaultEnableConfigurationSquiggles(): boolean | undefined { return super.Section.get("default.enableConfigurationSquiggles"); } + public get defaultCustomConfigurationVariables(): { [key: string]: string } | undefined { return super.Section.get< { [key: string]: string } >("default.customConfigurationVariables"); } public get useBacktickCommandSubstitution(): boolean | undefined { return super.Section.get("debugger.useBacktickCommandSubstitution"); } public get codeFolding(): boolean { return super.Section.get("codeFolding") === "Enabled"; }