Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dotconfig property for c_cpp_properties.json #7845

Merged
merged 8 commits into from
Feb 15, 2022
Merged
4 changes: 4 additions & 0 deletions Extension/c_cpp_properties.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@
"type": "string",
"pattern": "^\\d{2}\\.\\d{1}\\.\\d{5}\\.\\d{1}$|^8\\.1$"
},
"dotConfig": {
"description": "A path to a .config file created by Kconfig system. Kconfig system generates a file with all the defines to build a project. Examples of projects that use Kconfig system are the Linux Kernel and NuttX RTOS.",
"type": "string"
},
"defines": {
"markdownDescription": "A list of preprocessor definitions for the IntelliSense engine to use while parsing files. Optionally, use `=` to set a value, e.g. `VERSION=1`.",
"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.",
Expand Down
6 changes: 6 additions & 0 deletions Extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2472,6 +2472,12 @@
"markdownDescription": "%c_cpp.configuration.default.enableConfigurationSquiggles.markdownDescription%",
"scope": "resource"
},
"C_Cpp.default.dotConfig": {
"type": "string",
"default": null,
"markdownDescription": "%c_cpp.configuration.default.dotConfig.markdownDescription%",
"scope": "resource"
},
"C_Cpp.updateChannel": {
"type": "string",
"enum": [
Expand Down
1 change: 1 addition & 0 deletions Extension/package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@
"c_cpp.configuration.default.customConfigurationVariables.markdownDescription": { "message": "The value to use in a configuration if `customConfigurationVariables` is not set, or the values to insert if `${default}` is present as a key in `customConfigurationVariables`.", "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.updateChannel.markdownDescription": { "message": "Set to `Insiders` to automatically download and install the latest Insiders builds of the extension, which include upcoming features and bug fixes.", "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.updateChannel.deprecationMessage": "This setting is deprecated. Pre-release extensions are now available via the Marketplace.",
"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`.", "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.experimentalFeatures.description": "Controls whether \"experimental\" features are usable.",
"c_cpp.configuration.suggestSnippets.markdownDescription": { "message": "If `true`, snippets are provided by the language server.", "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.enhancedColorization.markdownDescription": { "message": "If enabled, code is colorized based on IntelliSense. This setting only applies if `#C_Cpp.intelliSenseEngine#` is 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." ] },
Expand Down
67 changes: 66 additions & 1 deletion Extension/src/LanguageServer/configurations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import * as nls from 'vscode-nls';
import { setTimeout } from 'timers';
import * as which from 'which';
import { WorkspaceBrowseConfiguration } from 'vscode-cpptools';
import { getOutputChannelLogger } from '../logger';

nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
Expand Down Expand Up @@ -67,6 +68,7 @@ export interface Configuration {
includePath?: string[];
macFrameworkPath?: string[];
windowsSdkVersion?: string;
dotConfig?: string;
defines?: string[];
intelliSenseMode?: string;
intelliSenseModeIsExplicit?: boolean;
Expand All @@ -86,6 +88,7 @@ export interface ConfigurationErrors {
macFrameworkPath?: string;
forcedInclude?: string;
compileCommands?: string;
dotConfig?: string;
browsePath?: string;
databaseFilename?: string;
}
Expand Down Expand Up @@ -787,6 +790,23 @@ export class CppProperties {
return this.resolveDefaultsDictionary(property, defaultValue, env);
}

private getDotconfigDefines(dotConfigPath: string): string[] {
const isWindows: boolean = os.platform() === 'win32';

if (dotConfigPath !== undefined) {
const path: string = this.resolvePath(dotConfigPath, isWindows);
try {
const configContent: string[] = fs.readFileSync(path, "utf-8").split("\n");
return configContent.filter(i => !i.startsWith("#") && i !== "");
} catch (errJS) {
const err: Error = errJS as Error;
getOutputChannelLogger().appendLine(`Invalid input, cannot resolve .config path: ${err.message}`);
}
}

return [];
}

private updateServerOnFolderSettingsChange(): void {
if (!this.configurationJson) {
return;
Expand All @@ -805,7 +825,15 @@ export class CppProperties {
configuration.includePath = includePath.concat(this.nodeAddonIncludes.filter(i => includePath.indexOf(i) < 0));
}
configuration.defines = this.updateConfigurationStringArray(configuration.defines, settings.defaultDefines, env);
configuration.macFrameworkPath = this.updateConfigurationPathsArray(configuration.macFrameworkPath, settings.defaultMacFrameworkPath, env);

// in case we have dotConfig
configuration.dotConfig = this.updateConfigurationString(configuration.dotConfig, settings.defaultDotconfig, env);
if (configuration.dotConfig !== undefined) {
configuration.defines = configuration.defines || [];
configuration.defines = configuration.defines.concat(this.getDotconfigDefines(configuration.dotConfig));
}

configuration.macFrameworkPath = this.updateConfigurationStringArray(configuration.macFrameworkPath, settings.defaultMacFrameworkPath, env);
configuration.windowsSdkVersion = this.updateConfigurationString(configuration.windowsSdkVersion, settings.defaultWindowsSdkVersion, env);
configuration.forcedInclude = this.updateConfigurationPathsArray(configuration.forcedInclude, settings.defaultForcedInclude, env);
configuration.compileCommands = this.updateConfigurationString(configuration.compileCommands, settings.defaultCompileCommands, env);
Expand Down Expand Up @@ -1445,6 +1473,7 @@ export class CppProperties {
// Validate files
errors.forcedInclude = this.validatePath(config.forcedInclude, false, true);
errors.compileCommands = this.validatePath(config.compileCommands, false);
errors.dotConfig = this.validatePath(config.dotConfig, false);
errors.databaseFilename = this.validatePath((config.browse ? config.browse.databaseFilename : undefined), false);

// Validate intelliSenseMode
Expand Down Expand Up @@ -1708,6 +1737,9 @@ export class CppProperties {
const compilerPathStart: number = curText.search(/\s*\"compilerPath\"\s*:\s*\"/);
const compilerPathValueStart: number = curText.indexOf('"', curText.indexOf(":", compilerPathStart));
const compilerPathEnd: number = compilerPathStart === -1 ? -1 : curText.indexOf('"', compilerPathValueStart + 1) + 1;
const dotConfigStart: number = curText.search(/\s*\"dotConfig\"\s*:\s*\"/);
const dotConfigValueStart: number = curText.indexOf('"', curText.indexOf(":", dotConfigStart));
const dotConfigEnd: number = dotConfigStart === -1 ? -1 : curText.indexOf('"', dotConfigValueStart + 1) + 1;
const processedPaths: Set<string> = new Set<string>();

// Validate compiler paths
Expand Down Expand Up @@ -1753,6 +1785,39 @@ export class CppProperties {
diagnostics.push(diagnostic);
}

// validate .config path
let dotConfigPath: string | undefined;
let dotConfigPathExists: boolean = true;
let dotConfigMessage: string | undefined;

dotConfigPath = currentConfiguration.dotConfig;
dotConfigPath = util.resolveVariables(dotConfigPath, this.ExtendedEnvironment).trim();
dotConfigPath = this.resolvePath(dotConfigPath, isWindows);
const isWSLDotConfig: boolean = isWindows && dotConfigPath.startsWith("/");
// does not try resolve if the dotConfig property is empty
dotConfigPath = dotConfigPath !== '' ? dotConfigPath : undefined;

if (dotConfigPath && this.rootUri) {
const checkPathExists: any = util.checkPathExistsSync(dotConfigPath, this.rootUri.fsPath + path.sep, isWindows, isWSLDotConfig, true);
dotConfigPathExists = checkPathExists.pathExists;
dotConfigPath = checkPathExists.path;
}
if (!dotConfigPathExists) {
dotConfigMessage = localize('cannot.find2', "Cannot find \"{0}\".", dotConfigPath);
newSquiggleMetrics.PathNonExistent++;
} else if (dotConfigPath && !util.checkFileExistsSync(dotConfigPath)) {
dotConfigMessage = localize("path.is.not.a.file", "Path is not a file: {0}", dotConfigPath);
newSquiggleMetrics.PathNotAFile++;
}

if (dotConfigMessage) {
const diagnostic: vscode.Diagnostic = new vscode.Diagnostic(
new vscode.Range(document.positionAt(curTextStartOffset + dotConfigValueStart),
document.positionAt(curTextStartOffset + dotConfigEnd)),
dotConfigMessage, vscode.DiagnosticSeverity.Warning);
diagnostics.push(diagnostic);
}

// Validate paths
for (const curPath of paths) {
if (processedPaths.has(curPath)) {
Expand Down
1 change: 1 addition & 0 deletions Extension/src/LanguageServer/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ export class CppSettings extends Settings {
public get filesExclude(): vscode.WorkspaceConfiguration | undefined { return super.Section.get<vscode.WorkspaceConfiguration>("files.exclude"); }
public get defaultIncludePath(): string[] | undefined { return super.getWithUndefinedDefault<string[]>("default.includePath"); }
public get defaultDefines(): string[] | undefined { return super.getWithUndefinedDefault<string[]>("default.defines"); }
public get defaultDotconfig(): string | undefined { return super.Section.get<string>("default.dotConfig"); }
public get defaultMacFrameworkPath(): string[] | undefined { return super.getWithUndefinedDefault<string[]>("default.macFrameworkPath"); }
public get defaultWindowsSdkVersion(): string | undefined { return super.Section.get<string>("default.windowsSdkVersion"); }
public get defaultCompileCommands(): string | undefined { return super.Section.get<string>("default.compileCommands"); }
Expand Down
4 changes: 4 additions & 0 deletions Extension/src/LanguageServer/settingsPanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const elementId: { [key: string]: string } = {
windowsSdkVersion: "windowsSdkVersion",
macFrameworkPath: "macFrameworkPath",
compileCommands: "compileCommands",
dotConfig: "dotConfig",
mergeConfigurations: "mergeConfigurations",
configurationProvider: "configurationProvider",
forcedInclude: "forcedInclude",
Expand Down Expand Up @@ -326,6 +327,9 @@ export class SettingsPanel {
case elementId.compileCommands:
this.configValues.compileCommands = message.value;
break;
case elementId.dotConfig:
this.configValues.dotConfig = message.value;
break;
case elementId.mergeConfigurations:
this.configValues.mergeConfigurations = message.value;
break;
Expand Down
9 changes: 9 additions & 0 deletions Extension/ui/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,15 @@
</div>
</div>

<div class="section">
<div class="section-title" data-loc-id="dot.config">Dot Config</div>
<div class="section-text" data-loc-id="dot.config.description">A path to a .config file created by Kconfig system. Kconfig system generates a file with all the defines to build a project. Examples of projects that use Kconfig system are the Linux Kernel and NuttX RTOS.</div>
<div>
<input name="inputValue" id="dotConfig" style="width: 798px"></input>
<div id="dotConfigInvalid" class="error" style="width: 800px"></div>
</div>
</div>

<div class="section">
<div class="section-title" data-loc-id="compile.commands">Compile commands</div>
<div class="section-text">
Expand Down
4 changes: 4 additions & 0 deletions Extension/ui/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ const elementId: { [key: string]: string } = {
forcedInclude: "forcedInclude",
forcedIncludeInvalid: "forcedIncludeInvalid",
mergeConfigurations: "mergeConfigurations",
dotConfig: "dotConfig",
dotConfigInvalid: "dotConfigInvalid",

// Browse properties
browsePath: "browsePath",
Expand Down Expand Up @@ -273,6 +275,7 @@ class SettingsApp {
(<HTMLInputElement>document.getElementById(elementId.mergeConfigurations)).checked = config.mergeConfigurations;
(<HTMLInputElement>document.getElementById(elementId.configurationProvider)).value = config.configurationProvider ? config.configurationProvider : "";
(<HTMLInputElement>document.getElementById(elementId.forcedInclude)).value = joinEntries(config.forcedInclude);
(<HTMLInputElement>document.getElementById(elementId.dotConfig)).value = config.dotConfig ? config.dotConfig : "";

if (config.browse) {
(<HTMLInputElement>document.getElementById(elementId.browsePath)).value = joinEntries(config.browse.path);
Expand Down Expand Up @@ -301,6 +304,7 @@ class SettingsApp {
this.showErrorWithInfo(elementId.compileCommandsInvalid, errors.compileCommands);
this.showErrorWithInfo(elementId.browsePathInvalid, errors.browsePath);
this.showErrorWithInfo(elementId.databaseFilenameInvalid, errors.databaseFilename);
this.showErrorWithInfo(elementId.dotConfigInvalid, errors.dotConfig);
} finally {
this.updating = false;
}
Expand Down