Skip to content

Commit 5f2444a

Browse files
committed
Implement per-workspace C/C++ configurations (#14363)
1 parent 86d415a commit 5f2444a

File tree

3 files changed

+121
-15
lines changed

3 files changed

+121
-15
lines changed

Extension/package.json

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,6 +1060,88 @@
10601060
"markdownDescription": "%c_cpp.configuration.default.recursiveIncludes.order.markdownDescription%",
10611061
"scope": "resource"
10621062
},
1063+
"C_Cpp.configurations": {
1064+
"type": "array",
1065+
"description": "A list of configurations that will be used instead of c_cpp_properties.json when present in workspace settings.",
1066+
"items": {
1067+
"type": "object",
1068+
"required": [
1069+
"name"
1070+
],
1071+
"properties": {
1072+
"name": {
1073+
"type": "string",
1074+
"description": "Configuration identifier."
1075+
},
1076+
"compilerPath": {
1077+
"type": [
1078+
"null",
1079+
"string"
1080+
],
1081+
"description": "Full path of the compiler being used."
1082+
},
1083+
"compilerArgs": {
1084+
"type": "array",
1085+
"items": {
1086+
"type": "string"
1087+
},
1088+
"description": "Compiler arguments."
1089+
},
1090+
"includePath": {
1091+
"type": "array",
1092+
"items": {
1093+
"type": "string"
1094+
},
1095+
"description": "A list of paths for the IntelliSense engine to use while searching for included headers."
1096+
},
1097+
"defines": {
1098+
"type": "array",
1099+
"items": {
1100+
"type": "string"
1101+
},
1102+
"description": "A list of preprocessor definitions."
1103+
},
1104+
"cStandard": {
1105+
"type": "string",
1106+
"description": "Version of the C language standard to use for IntelliSense."
1107+
},
1108+
"cppStandard": {
1109+
"type": "string",
1110+
"description": "Version of the C++ language standard to use for IntelliSense."
1111+
},
1112+
"intelliSenseMode": {
1113+
"type": "string",
1114+
"description": "The IntelliSense mode to use."
1115+
},
1116+
"configurationProvider": {
1117+
"type": "string",
1118+
"description": "The id of a VS Code extension that can provide IntelliSense configuration information."
1119+
},
1120+
"compileCommands": {
1121+
"type": "string",
1122+
"description": "Full path to a compile_commands.json file."
1123+
},
1124+
"browse": {
1125+
"type": "object",
1126+
"properties": {
1127+
"path": {
1128+
"type": "array",
1129+
"items": {
1130+
"type": "string"
1131+
}
1132+
},
1133+
"limitSymbolsToIncludedHeaders": {
1134+
"type": "boolean"
1135+
},
1136+
"databaseFilename": {
1137+
"type": "string"
1138+
}
1139+
}
1140+
}
1141+
}
1142+
},
1143+
"scope": "resource"
1144+
},
10631145
"C_Cpp.configurationWarnings": {
10641146
"type": "string",
10651147
"enum": [

Extension/src/LanguageServer/configurations.ts

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -363,8 +363,8 @@ export class CppProperties {
363363
public onDidChangeSettings(): void {
364364
// Default settings may have changed in a way that affects the configuration.
365365
// Just send another message since the language server will sort out whether anything important changed or not.
366-
if (!this.propertiesFile) {
367-
this.resetToDefaultSettings(true);
366+
const settings: CppSettings = new CppSettings(this.rootUri);
367+
if (!this.propertiesFile || (settings.configurations && settings.configurations.length > 0)) {
368368
this.handleConfigurationChange();
369369
} else if (!this.configurationIncomplete) {
370370
this.handleConfigurationChange();
@@ -1370,7 +1370,8 @@ export class CppProperties {
13701370
}
13711371

13721372
public handleConfigurationChange(): void {
1373-
if (this.propertiesFile === undefined) {
1373+
const settings: CppSettings = new CppSettings(this.rootUri);
1374+
if (this.propertiesFile === undefined && (!settings.configurations || settings.configurations.length === 0)) {
13741375
return; // Occurs when propertiesFile hasn't been checked yet.
13751376
}
13761377
this.configFileWatcherFallbackTime = new Date();
@@ -1452,24 +1453,46 @@ export class CppProperties {
14521453
}
14531454

14541455
private parsePropertiesFile(): boolean {
1455-
if (!this.propertiesFile) {
1456-
this.configurationJson = undefined;
1457-
return false;
1458-
}
1456+
const settings: CppSettings = new CppSettings(this.rootUri);
1457+
const settingsConfigs: any[] | undefined = settings.configurations;
1458+
14591459
let success: boolean = true;
14601460
const firstParse = this.configurationJson === undefined;
1461-
try {
1462-
const readResults: string = fs.readFileSync(this.propertiesFile.fsPath, 'utf8');
1463-
if (readResults === "") {
1464-
return false; // Repros randomly when the file is initially created. The parse will get called again after the file is written.
1461+
1462+
let newJson: ConfigurationJson | undefined;
1463+
if (settingsConfigs && settingsConfigs.length > 0) {
1464+
newJson = {
1465+
configurations: settingsConfigs as Configuration[],
1466+
version: configVersion
1467+
};
1468+
} else {
1469+
if (!this.propertiesFile) {
1470+
this.configurationJson = undefined;
1471+
return false;
14651472
}
1473+
try {
1474+
const readResults: string = fs.readFileSync(this.propertiesFile.fsPath, 'utf8');
1475+
if (readResults === "") {
1476+
return false; // Repros randomly when the file is initially created. The parse will get called again after the file is written.
1477+
}
14661478

1467-
// Try to use the same configuration as before the change.
1468-
// TODO?: Handle when jsonc.parse() throws an exception due to invalid JSON contents.
1469-
const newJson: ConfigurationJson = jsonc.parse(readResults, undefined, true) as any;
1470-
if (!newJson || !newJson.configurations || newJson.configurations.length === 0) {
1479+
// Try to use the same configuration as before the change.
1480+
// TODO?: Handle when jsonc.parse() throws an exception due to invalid JSON contents.
1481+
newJson = jsonc.parse(readResults, undefined, true) as any;
1482+
} catch (err) {
1483+
this.configurationJson = undefined;
1484+
success = false;
1485+
}
1486+
}
1487+
1488+
if (!newJson || !newJson.configurations || newJson.configurations.length === 0) {
1489+
if (settingsConfigs && settingsConfigs.length > 0) {
1490+
// If we tried to parse from settings and it was invalid, we should probably log an error.
1491+
} else if (this.propertiesFile) {
14711492
throw { message: localize("invalid.configuration.file", "Invalid configuration file. There must be at least one configuration present in the array.") };
14721493
}
1494+
return false;
1495+
}
14731496
if (!this.configurationIncomplete && this.configurationJson && this.configurationJson.configurations &&
14741497
this.CurrentConfigurationIndex >= 0 && this.CurrentConfigurationIndex < this.configurationJson.configurations.length) {
14751498
for (let i: number = 0; i < newJson.configurations.length; i++) {

Extension/src/LanguageServer/settings.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,7 @@ export class CppSettings extends Settings {
448448
public get defaultCStandard(): string | undefined { return this.getAsStringOrUndefined("default.cStandard"); }
449449
public get defaultCppStandard(): string | undefined { return this.getAsStringOrUndefined("default.cppStandard"); }
450450
public get defaultConfigurationProvider(): string | undefined { return changeBlankStringToUndefined(this.getAsStringOrUndefined("default.configurationProvider")); }
451+
public get configurations(): any[] | undefined { return this.Section.get<any[]>("configurations"); }
451452
public get defaultMergeConfigurations(): boolean { return this.getAsBoolean("default.mergeConfigurations"); }
452453
public get defaultBrowsePath(): string[] | undefined { return this.getArrayOfStringsWithUndefinedDefault("default.browse.path"); }
453454
public get defaultDatabaseFilename(): string | undefined { return changeBlankStringToUndefined(this.getAsStringOrUndefined("default.browse.databaseFilename")); }

0 commit comments

Comments
 (0)