diff --git a/Extension/c_cpp_properties.schema.json b/Extension/c_cpp_properties.schema.json index cd7e174d9..939cb8a34 100644 --- a/Extension/c_cpp_properties.schema.json +++ b/Extension/c_cpp_properties.schema.json @@ -180,7 +180,10 @@ "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" + "type": [ + "boolean", + "string" + ] }, "browse": { "type": "object", @@ -208,6 +211,42 @@ }, "additionalProperties": false }, + "recursiveIncludes": { + "type": "object", + "properties": { + "reduce": { + "markdownDescription": "Set to `always` to always reduce the number of recursive include paths provided to IntelliSense to only those paths currently referenced by #include statements. This requires first parsing files to determine which headers are included. Set to `never` to provide all recursive include paths to IntelliSense. Reducing the number of recursive include paths may improve IntelliSense performance when a very large number of recursive include paths are involved. Not reducing the number of recursive include paths can improve IntelliSense performance by avoiding the need to parse files to determine which include paths to provide. The `default` value is currently to reduce the number of recursive include paths provided to IntelliSense.", + "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": "string", + "enum": [ + "always", + "never", + "default", + "${default}" + ] + }, + "priority": { + "markdownDescription": "The priority of recursive include paths. If set to `beforeSystemIncludes`, the recursive include paths will be searched before system include paths. If set to `afterSystemIncludes`, the recursive include paths will be searched after system include paths. `beforeSystemIncludes` would more closely reflect the search order of a compiler, while `afterSystemIncludes` may result in improved performance.", + "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": "string", + "enum": [ + "beforeSystemIncludes", + "afterSystemIncludes", + "${default}" + ] + }, + "order": { + "markdownDescription": "The order in which subdirectories of recursive includes are searched.", + "type": "string", + "enum": [ + "depthFirst", + "breadthFirst", + "${default}" + ] + } + }, + "additionalProperties": false + }, "customConfigurationVariables": { "type": "object", "markdownDescription": "Custom variables that can be queried through the command `${cpptools:activeConfigCustomVariable}` to use for the input variables in `launch.json` or `tasks.json`.", diff --git a/Extension/package.json b/Extension/package.json index 93954fdb2..07c2455d3 100644 --- a/Extension/package.json +++ b/Extension/package.json @@ -897,6 +897,37 @@ "markdownDescription": "%c_cpp.configuration.default.dotConfig.markdownDescription%", "scope": "resource" }, + "C_Cpp.default.recursiveIncludes.reduce": { + "type": "string", + "enum": [ + "always", + "never", + "default" + ], + "default": "default", + "markdownDescription": "%c_cpp.configuration.default.recursiveIncludes.reduce.markdownDescription%", + "scope": "resource" + }, + "C_Cpp.default.recursiveIncludes.priority": { + "type": "string", + "enum": [ + "beforeSystemIncludes", + "afterSystemIncludes" + ], + "default": "afterSystemIncludes", + "markdownDescription": "%c_cpp.configuration.default.recursiveIncludes.priority.markdownDescription%", + "scope": "resource" + }, + "C_Cpp.default.recursiveIncludes.order": { + "type": "string", + "enum": [ + "depthFirst", + "breadthFirst" + ], + "default": "depthFirst", + "markdownDescription": "%c_cpp.configuration.default.recursiveIncludes.order.markdownDescription%", + "scope": "resource" + }, "C_Cpp.configurationWarnings": { "type": "string", "enum": [ diff --git a/Extension/package.nls.json b/Extension/package.nls.json index d8c3599a7..6d9d9d2b5 100644 --- a/Extension/package.nls.json +++ b/Extension/package.nls.json @@ -682,7 +682,7 @@ ] }, "c_cpp.configuration.default.mergeConfigurations.markdownDescription": { - "message": "Set to `true` to merge include paths, defines, and forced includes with those from a configuration provider.", + "message": "The value to use in a configuration if `mergeConfigurations` is either not specified or set to `${default}`.", "comment": [ "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." ] @@ -724,7 +724,25 @@ ] }, "c_cpp.configuration.default.dotConfig.markdownDescription": { - "message": "The value to use in a configuration if `dotConfig` is not specified, or the value to insert if `${default}` is present in `dotConfig`.", + "message": "The value to use in a configuration if `dotConfig` is either not specified or set to `${default}`.", + "comment": [ + "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." + ] + }, + "c_cpp.configuration.default.recursiveIncludes.reduce.markdownDescription": { + "message": "The value to use in a configuration if `recursiveIncludes.reduce` is either not specified or set to `${default}`.", + "comment": [ + "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." + ] + }, + "c_cpp.configuration.default.recursiveIncludes.priority.markdownDescription": { + "message": "The value to use in a configuration if `recursiveIncludes.priority` is either not specified or set to `${default}`.", + "comment": [ + "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." + ] + }, + "c_cpp.configuration.default.recursiveIncludes.order.markdownDescription": { + "message": "The value to use in a configuration if `recursiveIncludes.order` is either not specified or set to `${default}`.", "comment": [ "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." ] diff --git a/Extension/src/LanguageServer/configurations.ts b/Extension/src/LanguageServer/configurations.ts index 8be51b0a7..ccd7723f9 100644 --- a/Extension/src/LanguageServer/configurations.ts +++ b/Extension/src/LanguageServer/configurations.ts @@ -83,8 +83,9 @@ export interface Configuration { forcedInclude?: string[]; configurationProviderInCppPropertiesJson?: string; configurationProvider?: string; - mergeConfigurations?: boolean; + mergeConfigurations?: boolean | string; browse?: Browse; + recursiveIncludes?: RecursiveIncludes; customConfigurationVariables?: { [key: string]: string }; } @@ -107,6 +108,12 @@ export interface Browse { databaseFilename?: string; } +export interface RecursiveIncludes { + reduce?: string; + priority?: string; + order?: string; +} + export interface KnownCompiler { path: string; isC: boolean; @@ -813,13 +820,16 @@ export class CppProperties { return resolvedGlob; } - private updateConfigurationString(property: string | undefined | null, defaultValue: string | undefined | null, env: Environment, acceptBlank?: boolean): string | undefined { + private updateConfigurationString(property: string | undefined | null, defaultValue: string | undefined | null, env?: Environment, acceptBlank?: boolean): string | undefined { if (property === null || property === undefined || property === "${default}") { property = defaultValue; } if (property === null || property === undefined || (acceptBlank !== true && property === "")) { return undefined; } + if (env === undefined) { + return property; + } return util.resolveVariables(property, env); } @@ -843,21 +853,8 @@ export class CppProperties { return paths; } - private updateConfigurationStringOrBoolean(property: string | boolean | undefined | null, defaultValue: boolean | undefined | null, env: Environment): string | boolean | undefined { - if (!property || property === "${default}") { - property = defaultValue; - } - if (!property || property === "") { - return undefined; - } - if (typeof property === "boolean") { - return property; - } - return util.resolveVariables(property, env); - } - - private updateConfigurationBoolean(property: boolean | undefined | null, defaultValue: boolean | undefined | null): boolean | undefined { - if (property === null || property === undefined) { + private updateConfigurationBoolean(property: boolean | string | undefined | null, defaultValue: boolean | undefined | null): boolean | undefined { + if (property === null || property === undefined || property === "${default}") { property = defaultValue; } @@ -865,7 +862,7 @@ export class CppProperties { return undefined; } - return property; + return property === true || property === "true"; } private updateConfigurationStringDictionary(property: { [key: string]: string } | undefined, defaultValue: { [key: string]: string } | undefined, env: Environment): { [key: string]: string } | undefined { @@ -939,6 +936,12 @@ export class CppProperties { configuration.cStandardIsExplicit = configuration.cStandardIsExplicit || settings.defaultCStandard !== ""; configuration.cppStandardIsExplicit = configuration.cppStandardIsExplicit || settings.defaultCppStandard !== ""; configuration.mergeConfigurations = this.updateConfigurationBoolean(configuration.mergeConfigurations, settings.defaultMergeConfigurations); + if (!configuration.recursiveIncludes) { + configuration.recursiveIncludes = {}; + } + configuration.recursiveIncludes.reduce = this.updateConfigurationString(configuration.recursiveIncludes.reduce, settings.defaultRecursiveIncludesReduce); + configuration.recursiveIncludes.priority = this.updateConfigurationString(configuration.recursiveIncludes.priority, settings.defaultRecursiveIncludesPriority); + configuration.recursiveIncludes.order = this.updateConfigurationString(configuration.recursiveIncludes.order, settings.defaultRecursiveIncludesOrder); if (!configuration.compileCommands) { // compile_commands.json already specifies a compiler. compilerPath overrides the compile_commands.json compiler so // don't set a default when compileCommands is in use. @@ -1002,7 +1005,7 @@ export class CppProperties { configuration.browse.path = this.updateConfigurationPathsArray(configuration.browse.path, settings.defaultBrowsePath, env); } - configuration.browse.limitSymbolsToIncludedHeaders = this.updateConfigurationStringOrBoolean(configuration.browse.limitSymbolsToIncludedHeaders, settings.defaultLimitSymbolsToIncludedHeaders, env); + configuration.browse.limitSymbolsToIncludedHeaders = this.updateConfigurationBoolean(configuration.browse.limitSymbolsToIncludedHeaders, settings.defaultLimitSymbolsToIncludedHeaders); configuration.browse.databaseFilename = this.updateConfigurationString(configuration.browse.databaseFilename, settings.defaultDatabaseFilename, env); if (i === this.CurrentConfigurationIndex) { diff --git a/Extension/src/LanguageServer/settings.ts b/Extension/src/LanguageServer/settings.ts index 58a28e87b..fb8b3c458 100644 --- a/Extension/src/LanguageServer/settings.ts +++ b/Extension/src/LanguageServer/settings.ts @@ -444,6 +444,9 @@ export class CppSettings extends Settings { 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"); } + public get defaultRecursiveIncludesReduce(): string { return this.getAsString("default.recursiveIncludes.reduce"); } + public get defaultRecursiveIncludesPriority(): string { return this.getAsString("default.recursiveIncludes.priority"); } + public get defaultRecursiveIncludesOrder(): string { return this.getAsString("default.recursiveIncludes.order"); } public get defaultSystemIncludePath(): string[] | undefined { return this.getArrayOfStringsWithUndefinedDefault("default.systemIncludePath"); } public get defaultEnableConfigurationSquiggles(): boolean { return this.getAsBoolean("default.enableConfigurationSquiggles"); } public get defaultCustomConfigurationVariables(): Associations | undefined { return this.getAsAssociations("default.customConfigurationVariables", true) ?? undefined; } diff --git a/Extension/src/LanguageServer/settingsPanel.ts b/Extension/src/LanguageServer/settingsPanel.ts index a13ef8109..6352e428f 100644 --- a/Extension/src/LanguageServer/settingsPanel.ts +++ b/Extension/src/LanguageServer/settingsPanel.ts @@ -52,6 +52,9 @@ const elementId: { [key: string]: string } = { mergeConfigurations: "mergeConfigurations", configurationProvider: "configurationProvider", forcedInclude: "forcedInclude", + recursiveIncludesReduce: "recursiveIncludes.reduce", + recursiveIncludesPriority: "recursiveIncludes.priority", + recursiveIncludesOrder: "recursiveIncludes.order", // Browse properties browsePath: "browsePath", @@ -351,6 +354,24 @@ export class SettingsPanel { case elementId.forcedInclude: this.configValues.forcedInclude = splitEntries(message.value); break; + case elementId.recursiveIncludesReduce: + if (!this.configValues.recursiveIncludes) { + this.configValues.recursiveIncludes = {}; + } + this.configValues.recursiveIncludes.reduce = message.value; + break; + case elementId.recursiveIncludesPriority: + if (!this.configValues.recursiveIncludes) { + this.configValues.recursiveIncludes = {}; + } + this.configValues.recursiveIncludes.priority = message.value; + break; + case elementId.recursiveIncludesOrder: + if (!this.configValues.recursiveIncludes) { + this.configValues.recursiveIncludes = {}; + } + this.configValues.recursiveIncludes.order = message.value; + break; case elementId.browsePath: if (!this.configValues.browse) { this.configValues.browse = {}; diff --git a/Extension/ui/settings.html b/Extension/ui/settings.html index 5bfe02051..a8deeb3c3 100644 --- a/Extension/ui/settings.html +++ b/Extension/ui/settings.html @@ -722,6 +722,49 @@ +
always to reduce the number of recursive include paths provided to IntelliSense to only those paths currently referenced by #include statements. This requires first parsing files to determine which files are included. Set to never to provide all recursive include paths to IntelliSense. Reducing the number of recursive include paths may improve IntelliSense performance when a very large number of recursive include paths are involved. Not reducing the number of recursive include paths can improve IntelliSense performance by avoiding the need to parse files to determine which include paths to provide.
+ beforeSystemIncludes, the recursive include paths will be searched before system include paths. If set to afterSystemIncludes, the recursive include paths will be searched after system include paths.
+