Apply mergeConfigurations for browse.path, auto-update the config, and avoid accumulating old configs (#13678)

* Apply mergeConfigurations for browse.path.
* Fix a bug with old merge properties being added.
This commit is contained in:
Sean McManus
2025-06-13 15:07:35 -07:00
committed by GitHub
parent ad8c3d8947
commit bd97021284
7 changed files with 104 additions and 28 deletions
+3 -6
View File
@@ -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",
+1
View File
@@ -841,6 +841,7 @@
},
"C_Cpp.default.mergeConfigurations": {
"type": "boolean",
"default": false,
"markdownDescription": "%c_cpp.configuration.default.mergeConfigurations.markdownDescription%",
"scope": "resource"
},
+44 -4
View File
@@ -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);
}
+36 -1
View File
@@ -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) {
+1 -16
View File
@@ -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<any>(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);
}
+18
View File
@@ -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;
}
+1 -1
View File
@@ -687,7 +687,7 @@
<div class="section-title" data-loc-id="merge.configurations">Merge configurations</div>
<div>
<input type="checkbox" id="mergeConfigurations" style="vertical-align: middle; transform: scale(1.5)">
<span data-loc-id="merge.configurations.description">When <code>true</code> (or checked), merge include paths, defines, and forced includes with those from a configuration provider.</span>
<span data-loc-id="merge.configurations.description">When <code>true</code> (or checked), merge <code>includePath</code>, <code>defines</code>, <code>forcedInclude</code>, and <code>browse.path</code> with those received from the configuration provider.</span>
</input>
</div>
</div>