diff --git a/Extension/c_cpp_properties.schema.json b/Extension/c_cpp_properties.schema.json index 6e69667e7..1760634e9 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.", + "descriptionHint": "{Locked=\"`true`\"} {Locked=\"`includePath`\"} {Locked=\"`defines`\"} {Locked=\"`forcedInclude`\"} {Locked=\"`browse.path`\"}", + "type": "boolean" }, "browse": { "type": "object", 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 fdd0eb737..1b33615b0 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'; @@ -889,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; @@ -2181,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 => { @@ -3139,11 +3145,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); } diff --git a/Extension/src/LanguageServer/configurations.ts b/Extension/src/LanguageServer/configurations.ts index 91268b499..8a08b9987 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 }; @@ -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 001feecc6..c382c0ca7 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.