From 036e29797bb2b76b265926d669e37066e5916e34 Mon Sep 17 00:00:00 2001 From: Sean McManus Date: Fri, 6 Jun 2025 17:47:40 -0700 Subject: [PATCH 1/5] Apply mergeConfigurations for browse.path. --- Extension/c_cpp_properties.schema.json | 9 +++------ Extension/src/LanguageServer/client.ts | 4 +++- Extension/src/LanguageServer/configurations.ts | 2 +- Extension/ui/settings.html | 2 +- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Extension/c_cpp_properties.schema.json b/Extension/c_cpp_properties.schema.json index 6e69667e7..cb1ba7f9e 100644 --- a/Extension/c_cpp_properties.schema.json +++ b/Extension/c_cpp_properties.schema.json @@ -180,12 +180,9 @@ "type": "string" }, "mergeConfigurations": { - "markdownDescription": "Set to `true` to merge include paths, defines, and forced includes with those from a configuration provider.", - "descriptionHint": "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered.", - "type": [ - "boolean", - "string" - ] + "markdownDescription": "Set to `true` to merge `includePath`, `defines`, `forcedInclude`, and `browse.path` with those received from the configuration provider. Changes to `mergeConfigurations` won't take effect until the configuration provider resends the configuration.", + "descriptionHint": "{Locked=\"`true`\"} {Locked=\"`includePath`\"} {Locked=\"`defines`\"} {Locked=\"`forcedInclude`\"} {Locked=\"`browsePath`\"} {Locked=\"`mergeConfigurations`\"}", + "type": "boolean" }, "browse": { "type": "object", diff --git a/Extension/src/LanguageServer/client.ts b/Extension/src/LanguageServer/client.ts index fdd0eb737..2eb022188 100644 --- a/Extension/src/LanguageServer/client.ts +++ b/Extension/src/LanguageServer/client.ts @@ -244,6 +244,7 @@ interface CustomConfigurationParams extends WorkspaceFolderParams { interface CustomBrowseConfigurationParams extends WorkspaceFolderParams { browseConfiguration: InternalWorkspaceBrowseConfiguration; + mergeConfigurations: boolean; } interface CompileCommandsPaths extends WorkspaceFolderParams { @@ -3349,7 +3350,8 @@ export class DefaultClient implements Client { const params: CustomBrowseConfigurationParams = { browseConfiguration: sanitized, - workspaceFolderUri: this.RootUri?.toString() + workspaceFolderUri: this.RootUri?.toString(), + mergeConfigurations: this.configuration.CurrentConfiguration?.mergeConfigurations ?? false }; void this.languageClient.sendNotification(CustomBrowseConfigurationNotification, params).catch(logAndReturn.undefined); diff --git a/Extension/src/LanguageServer/configurations.ts b/Extension/src/LanguageServer/configurations.ts index 91268b499..c9c1df931 100644 --- a/Extension/src/LanguageServer/configurations.ts +++ b/Extension/src/LanguageServer/configurations.ts @@ -83,7 +83,7 @@ export interface Configuration { forcedInclude?: string[]; configurationProviderInCppPropertiesJson?: string; configurationProvider?: string; - mergeConfigurations?: boolean | string; + mergeConfigurations?: boolean; browse?: Browse; recursiveIncludes?: RecursiveIncludes; customConfigurationVariables?: { [key: string]: string }; diff --git a/Extension/ui/settings.html b/Extension/ui/settings.html index 001feecc6..ca7b6eb76 100644 --- a/Extension/ui/settings.html +++ b/Extension/ui/settings.html @@ -687,7 +687,7 @@
Merge configurations
- When true (or checked), merge include paths, defines, and forced includes with those from a configuration provider. + When true (or checked), merge includePath, defines, forcedInclude, and browse.path with those received from the configuration provider. Changes to mergeConfigurations won't take effect until the the configuration provider resends the configuration.
From 86ff33804d36f3201a2f72958ffb6861bd229d57 Mon Sep 17 00:00:00 2001 From: Sean McManus Date: Fri, 6 Jun 2025 18:15:11 -0700 Subject: [PATCH 2/5] Fix Locked string reference. --- Extension/c_cpp_properties.schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Extension/c_cpp_properties.schema.json b/Extension/c_cpp_properties.schema.json index cb1ba7f9e..980ad6249 100644 --- a/Extension/c_cpp_properties.schema.json +++ b/Extension/c_cpp_properties.schema.json @@ -181,7 +181,7 @@ }, "mergeConfigurations": { "markdownDescription": "Set to `true` to merge `includePath`, `defines`, `forcedInclude`, and `browse.path` with those received from the configuration provider. Changes to `mergeConfigurations` won't take effect until the configuration provider resends the configuration.", - "descriptionHint": "{Locked=\"`true`\"} {Locked=\"`includePath`\"} {Locked=\"`defines`\"} {Locked=\"`forcedInclude`\"} {Locked=\"`browsePath`\"} {Locked=\"`mergeConfigurations`\"}", + "descriptionHint": "{Locked=\"`true`\"} {Locked=\"`includePath`\"} {Locked=\"`defines`\"} {Locked=\"`forcedInclude`\"} {Locked=\"`browse.path`\"} {Locked=\"`mergeConfigurations`\"}", "type": "boolean" }, "browse": { From 0545a5b3769de3f9e7a8eb3d0b2d1ca4e8d94a53 Mon Sep 17 00:00:00 2001 From: Sean McManus Date: Mon, 9 Jun 2025 19:49:22 -0700 Subject: [PATCH 3/5] Update. --- Extension/c_cpp_properties.schema.json | 4 +- Extension/package.json | 1 + Extension/src/LanguageServer/client.ts | 51 ++++++++++++++++--- .../src/LanguageServer/configurations.ts | 35 +++++++++++++ Extension/src/LanguageServer/settings.ts | 17 +------ Extension/src/common.ts | 18 +++++++ Extension/ui/settings.html | 2 +- 7 files changed, 102 insertions(+), 26 deletions(-) diff --git a/Extension/c_cpp_properties.schema.json b/Extension/c_cpp_properties.schema.json index 980ad6249..1760634e9 100644 --- a/Extension/c_cpp_properties.schema.json +++ b/Extension/c_cpp_properties.schema.json @@ -180,8 +180,8 @@ "type": "string" }, "mergeConfigurations": { - "markdownDescription": "Set to `true` to merge `includePath`, `defines`, `forcedInclude`, and `browse.path` with those received from the configuration provider. Changes to `mergeConfigurations` won't take effect until the configuration provider resends the configuration.", - "descriptionHint": "{Locked=\"`true`\"} {Locked=\"`includePath`\"} {Locked=\"`defines`\"} {Locked=\"`forcedInclude`\"} {Locked=\"`browse.path`\"} {Locked=\"`mergeConfigurations`\"}", + "markdownDescription": "Set to `true` to merge `includePath`, `defines`, `forcedInclude`, and `browse.path` with those received from the configuration provider.", + "descriptionHint": "{Locked=\"`true`\"} {Locked=\"`includePath`\"} {Locked=\"`defines`\"} {Locked=\"`forcedInclude`\"} {Locked=\"`browse.path`\"}", "type": "boolean" }, "browse": { diff --git a/Extension/package.json b/Extension/package.json index 9767d9b06..27bdbbb3c 100644 --- a/Extension/package.json +++ b/Extension/package.json @@ -841,6 +841,7 @@ }, "C_Cpp.default.mergeConfigurations": { "type": "boolean", + "default": false, "markdownDescription": "%c_cpp.configuration.default.mergeConfigurations.markdownDescription%", "scope": "resource" }, diff --git a/Extension/src/LanguageServer/client.ts b/Extension/src/LanguageServer/client.ts index 2eb022188..40bcd8ac5 100644 --- a/Extension/src/LanguageServer/client.ts +++ b/Extension/src/LanguageServer/client.ts @@ -32,7 +32,6 @@ import { CloseAction, DidOpenTextDocumentParams, ErrorAction, LanguageClientOpti import { LanguageClient, ServerOptions } from 'vscode-languageclient/node'; import * as nls from 'vscode-nls'; import { DebugConfigurationProvider } from '../Debugger/configurationProvider'; -import { CustomConfigurationProvider1, getCustomConfigProviders, isSameProviderExtensionId } from '../LanguageServer/customProviders'; import { ManualPromise } from '../Utility/Async/manualPromise'; import { ManualSignal } from '../Utility/Async/manualSignal'; import { logAndReturn } from '../Utility/Async/returns'; @@ -57,6 +56,7 @@ import { import { Location, TextEdit, WorkspaceEdit } from './commonTypes'; import * as configs from './configurations'; import { CopilotCompletionContextFeatures, CopilotCompletionContextProvider } from './copilotCompletionContextProvider'; +import { CustomConfigurationProvider1, getCustomConfigProviders, isSameProviderExtensionId } from './customProviders'; import { DataBinding } from './dataBinding'; import { cachedEditorConfigSettings, getEditorConfigSettings } from './editorConfig'; import { CppSourceStr, clients, configPrefix, initializeIntervalTimer, updateLanguageConfigurations, usesCrashHandler, watchForCrashes } from './extension'; @@ -244,7 +244,6 @@ interface CustomConfigurationParams extends WorkspaceFolderParams { interface CustomBrowseConfigurationParams extends WorkspaceFolderParams { browseConfiguration: InternalWorkspaceBrowseConfiguration; - mergeConfigurations: boolean; } interface CompileCommandsPaths extends WorkspaceFolderParams { @@ -890,6 +889,11 @@ export class DefaultClient implements Client { private settingsTracker: SettingsTracker; private loggingLevel: number = 1; private configurationProvider?: string; + private mergeConfigurations: boolean = false; + private includePath?: string[]; + private defines?: string[]; + private forcedInclude?: string[]; + private browsePath?: string[]; private hoverProvider: HoverProvider | undefined; private copilotHoverProvider: CopilotHoverProvider | undefined; private copilotCompletionProvider?: CopilotCompletionContextProvider; @@ -3140,11 +3144,45 @@ export class DefaultClient implements Client { const configName: string | undefined = configurations[params.currentConfiguration].name ?? ""; this.model.activeConfigName.setValueIfActive(configName); const newProvider: string | undefined = this.configuration.CurrentConfigurationProvider; - if (!isSameProviderExtensionId(newProvider, this.configurationProvider)) { - if (this.configurationProvider) { + const previousProvider: string | undefined = this.configurationProvider; + let updateCustomConfigs: boolean = false; + if (!isSameProviderExtensionId(previousProvider, newProvider)) { + this.configurationProvider = newProvider; + updateCustomConfigs = true; + } + if (newProvider !== undefined) { + const newMergeConfigurations: boolean = this.configuration.CurrentMergeConfigurations; + if (this.mergeConfigurations != newMergeConfigurations) { + this.mergeConfigurations = newMergeConfigurations; + updateCustomConfigs = true; + } + if (newMergeConfigurations) { + const newIncludePath: string[] | undefined = this.configuration.CurrentIncludePath; + if (!util.equals(this.includePath, newIncludePath)) { + this.includePath = newIncludePath; + updateCustomConfigs = true; + } + const newDefines: string[] | undefined = this.configuration.CurrentDefines; + if (!util.equals(this.defines, newDefines)) { + this.defines = newDefines; + updateCustomConfigs = true; + } + const newForcedInclude: string[] | undefined = this.configuration.CurrentForcedInclude; + if (!util.equals(this.forcedInclude, newForcedInclude)) { + this.forcedInclude = newForcedInclude; + updateCustomConfigs = true; + } + const newBrowsePath: string[] | undefined = this.configuration.CurrentBrowsePath; + if (!util.equals(this.browsePath, newBrowsePath)) { + this.browsePath = newBrowsePath; + updateCustomConfigs = true; + } + } + } + if (updateCustomConfigs) { + if (previousProvider) { void this.clearCustomBrowseConfiguration().catch(logAndReturn.undefined); } - this.configurationProvider = newProvider; void this.updateCustomBrowseConfiguration().catch(logAndReturn.undefined); void this.updateCustomConfigurations().catch(logAndReturn.undefined); } @@ -3350,8 +3388,7 @@ export class DefaultClient implements Client { const params: CustomBrowseConfigurationParams = { browseConfiguration: sanitized, - workspaceFolderUri: this.RootUri?.toString(), - mergeConfigurations: this.configuration.CurrentConfiguration?.mergeConfigurations ?? false + workspaceFolderUri: this.RootUri?.toString() }; void this.languageClient.sendNotification(CustomBrowseConfigurationNotification, params).catch(logAndReturn.undefined); diff --git a/Extension/src/LanguageServer/configurations.ts b/Extension/src/LanguageServer/configurations.ts index c9c1df931..8a08b9987 100644 --- a/Extension/src/LanguageServer/configurations.ts +++ b/Extension/src/LanguageServer/configurations.ts @@ -204,6 +204,41 @@ export class CppProperties { return new CppSettings(this.rootUri).defaultConfigurationProvider; } + public get CurrentMergeConfigurations(): boolean { + if (this.CurrentConfiguration?.mergeConfigurations) { + return this.CurrentConfiguration.mergeConfigurations; + } + return new CppSettings(this.rootUri).defaultMergeConfigurations; + } + + public get CurrentIncludePath(): string[] | undefined { + if (this.CurrentConfiguration?.includePath) { + return this.CurrentConfiguration.includePath; + } + return new CppSettings(this.rootUri).defaultIncludePath; + } + + public get CurrentDefines(): string[] | undefined { + if (this.CurrentConfiguration?.defines) { + return this.CurrentConfiguration.defines; + } + return new CppSettings(this.rootUri).defaultDefines; + } + + public get CurrentForcedInclude(): string[] | undefined { + if (this.CurrentConfiguration?.forcedInclude) { + return this.CurrentConfiguration.forcedInclude; + } + return new CppSettings(this.rootUri).defaultForcedInclude; + } + + public get CurrentBrowsePath(): string[] | undefined { + if (this.CurrentConfiguration?.browse?.path) { + return this.CurrentConfiguration.browse.path; + } + return new CppSettings(this.rootUri).defaultBrowsePath; + } + public get ConfigurationNames(): string[] | undefined { const result: string[] = []; if (this.configurationJson) { diff --git a/Extension/src/LanguageServer/settings.ts b/Extension/src/LanguageServer/settings.ts index 449143439..0f35cc315 100644 --- a/Extension/src/LanguageServer/settings.ts +++ b/Extension/src/LanguageServer/settings.ts @@ -440,7 +440,7 @@ export class CppSettings extends Settings { public get defaultCStandard(): string | undefined { return this.getAsStringOrUndefined("default.cStandard"); } public get defaultCppStandard(): string | undefined { return this.getAsStringOrUndefined("default.cppStandard"); } public get defaultConfigurationProvider(): string | undefined { return changeBlankStringToUndefined(this.getAsStringOrUndefined("default.configurationProvider")); } - public get defaultMergeConfigurations(): boolean | undefined { return this.getAsBooleanOrUndefined("default.mergeConfigurations"); } + public get defaultMergeConfigurations(): boolean { return this.getAsBoolean("default.mergeConfigurations"); } public get defaultBrowsePath(): string[] | undefined { return this.getArrayOfStringsWithUndefinedDefault("default.browse.path"); } public get defaultDatabaseFilename(): string | undefined { return changeBlankStringToUndefined(this.getAsStringOrUndefined("default.browse.databaseFilename")); } public get defaultLimitSymbolsToIncludedHeaders(): boolean { return this.getAsBoolean("default.browse.limitSymbolsToIncludedHeaders"); } @@ -569,21 +569,6 @@ export class CppSettings extends Settings { return undefined; } - // Returns the value of a setting as a boolean with proper type validation and checks for valid enum values while returning an undefined value if necessary. - private getAsBooleanOrUndefined(settingName: string): boolean | undefined { - const value: any = super.Section.get(settingName); - const setting = getRawSetting("C_Cpp." + settingName, true); - if (setting.default !== undefined) { - console.error(`Default value for ${settingName} is expected to be undefined.`); - } - - if (isBoolean(value)) { - return value; - } - - return undefined; - } - private isValidDefault(isValid: (x: any) => boolean, value: any, allowNull: boolean): boolean { return isValid(value) || (allowNull && value === null); } diff --git a/Extension/src/common.ts b/Extension/src/common.ts index a48326eae..4ce922d28 100644 --- a/Extension/src/common.ts +++ b/Extension/src/common.ts @@ -1810,3 +1810,21 @@ export function findExePathInArgs(args: CommandString[]): string | undefined { export function getVsCodeVersion(): number[] { return vscode.version.split('.').map(num => parseInt(num, undefined)); } + +export function equals(array1: string[] | undefined, array2: string[] | undefined): boolean { + if (array1 === undefined && array2 === undefined) { + return true; + } + if (array1 === undefined || array2 === undefined) { + return false; + } + if (array1.length !== array2.length) { + return false; + } + for (let i: number = 0; i < array1.length; ++i) { + if (array1[i] !== array2[i]) { + return false; + } + } + return true; +} diff --git a/Extension/ui/settings.html b/Extension/ui/settings.html index ca7b6eb76..c382c0ca7 100644 --- a/Extension/ui/settings.html +++ b/Extension/ui/settings.html @@ -687,7 +687,7 @@
Merge configurations
- When true (or checked), merge includePath, defines, forcedInclude, and browse.path with those received from the configuration provider. Changes to mergeConfigurations won't take effect until the the configuration provider resends the configuration. + When true (or checked), merge includePath, defines, forcedInclude, and browse.path with those received from the configuration provider.
From 25c01b45741f94379fffdef20eb3bd5c4e0d6a45 Mon Sep 17 00:00:00 2001 From: Sean McManus Date: Mon, 9 Jun 2025 19:55:39 -0700 Subject: [PATCH 4/5] Fix linter. --- Extension/src/LanguageServer/client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Extension/src/LanguageServer/client.ts b/Extension/src/LanguageServer/client.ts index 40bcd8ac5..bdd3fdce9 100644 --- a/Extension/src/LanguageServer/client.ts +++ b/Extension/src/LanguageServer/client.ts @@ -3152,7 +3152,7 @@ export class DefaultClient implements Client { } if (newProvider !== undefined) { const newMergeConfigurations: boolean = this.configuration.CurrentMergeConfigurations; - if (this.mergeConfigurations != newMergeConfigurations) { + if (this.mergeConfigurations !== newMergeConfigurations) { this.mergeConfigurations = newMergeConfigurations; updateCustomConfigs = true; } From cc1eb014c615320c99c2954ae10c5983884b2c72 Mon Sep 17 00:00:00 2001 From: Sean McManus Date: Tue, 10 Jun 2025 14:35:05 -0700 Subject: [PATCH 5/5] Fix a bug with old merge properties being added. --- Extension/src/LanguageServer/client.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/Extension/src/LanguageServer/client.ts b/Extension/src/LanguageServer/client.ts index bdd3fdce9..1b33615b0 100644 --- a/Extension/src/LanguageServer/client.ts +++ b/Extension/src/LanguageServer/client.ts @@ -2186,6 +2186,7 @@ export class DefaultClient implements Client { if (configs && configs.length > 0 && configs[0]) { const fileConfiguration: configs.Configuration | undefined = this.configuration.CurrentConfiguration; if (fileConfiguration?.mergeConfigurations) { + configs = deepCopy(configs); configs.forEach(config => { if (fileConfiguration.includePath) { fileConfiguration.includePath.forEach(p => {