Skip to content

Commit

Permalink
show a Squiggle if there is a duplicate configuration name (#6752)
Browse files Browse the repository at this point in the history
* change master to main

* check for duplicate names

* check duplicates before removing the later configs

* spelling check

* fix spelling error

* add configNameInvalid for UI error(won't show yet)

* show the UI error

* squiggle for all duplicates

* change let to const

* squiggle for first one as well

* let to const
  • Loading branch information
elahehrashedi authored Jan 14, 2021
1 parent 02c547b commit 1145a49
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 2 deletions.
56 changes: 55 additions & 1 deletion Extension/src/LanguageServer/configurations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export interface Configuration {
}

export interface ConfigurationErrors {
name?: string;
compilerPath?: string;
includePath?: string;
intelliSenseMode?: string;
Expand Down Expand Up @@ -1145,6 +1146,9 @@ export class CppProperties {
const isWindows: boolean = os.platform() === 'win32';
const config: Configuration = this.configurationJson.configurations[configIndex];

// Check if config name is unique.
errors.name = this.isConfigNameUnique(config.name);

// Validate compilerPath
let resolvedCompilerPath: string | undefined = this.resolvePath(config.compilerPath, isWindows);
const compilerPathAndArgs: util.CompilerPathAndArgs = util.extractCompilerPathAndArgs(resolvedCompilerPath);
Expand Down Expand Up @@ -1293,6 +1297,15 @@ export class CppProperties {
return errorMsg;
}

private isConfigNameUnique(configName: string): string | undefined {
let errorMsg: string | undefined;
const occurrences: number | undefined = this.ConfigurationNames?.filter(function (name): boolean { return name === configName; }).length;
if (occurrences) {
errorMsg = localize('duplicate.name', "{0} is a duplicate. The configuration name should be unique.", configName);
}
return errorMsg;
}

private handleSquiggles(): void {
if (!this.propertiesFile) {
return;
Expand Down Expand Up @@ -1334,8 +1347,49 @@ export class CppProperties {
envText = curText.substr(envStart, envEnd);
const envTextStartOffSet: number = envStart + 1;

// Check if all config names are unique.
let allConfigText: string = curText;
let allConfigTextOffset: number = envTextStartOffSet;
const nameRegex: RegExp = new RegExp(`{\\s*"name"\\s*:\\s*".*"`);
let configStart: number = allConfigText.search(new RegExp(nameRegex));
let configNameStart: number;
let configNameEnd: number;
let configName: string;
const configNames: Map<string, vscode.Range[]> = new Map<string, []>();
let dupErrorMsg: string;
while (configStart !== -1) {
allConfigText = allConfigText.substr(configStart);
allConfigTextOffset += configStart;
configNameStart = allConfigText.indexOf('"', allConfigText.indexOf(':') + 1) + 1;
configNameEnd = allConfigText.indexOf('"', configNameStart);
configName = allConfigText.substr(configNameStart, configNameEnd - configNameStart);
const newRange: vscode.Range = new vscode.Range(0, allConfigTextOffset + configNameStart, 0, allConfigTextOffset + configNameEnd);
const allRanges: vscode.Range[] | undefined = configNames.get(configName);
if (allRanges) {
allRanges.push(newRange);
configNames.set(configName, allRanges);
} else {
configNames.set(configName, [newRange]);
}
allConfigText = allConfigText.substr(configNameEnd + 1);
allConfigTextOffset += configNameEnd + 1;
configStart = allConfigText.search(new RegExp(nameRegex));
}
for (const [configName, allRanges] of configNames) {
if (allRanges && allRanges.length > 1) {
dupErrorMsg = localize('duplicate.name', "{0} is a duplicate. The configuration name should be unique.", configName);
allRanges.forEach(nameRange => {
const diagnostic: vscode.Diagnostic = new vscode.Diagnostic(
new vscode.Range(document.positionAt(nameRange.start.character),
document.positionAt(nameRange.end.character)),
dupErrorMsg, vscode.DiagnosticSeverity.Warning);
diagnostics.push(diagnostic);
});
}
}

// Get current config text
const configStart: number = curText.search(new RegExp(`{\\s*"name"\\s*:\\s*"${escapeStringRegExp(currentConfiguration.name)}"`));
configStart = curText.search(new RegExp(`{\\s*"name"\\s*:\\s*"${escapeStringRegExp(currentConfiguration.name)}"`));
if (configStart === -1) {
telemetry.logLanguageServerEvent("ConfigSquiggles", { "error": "config name not first" });
return;
Expand Down
1 change: 1 addition & 0 deletions Extension/src/LanguageServer/settingsPanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import * as telemetry from '../telemetry';
const elementId: { [key: string]: string } = {
// Basic settings
configName: "configName",
configNameInvalid: "configNameInvalid",
configSelection: "configSelection",
addConfigBtn: "addConfigBtn",
addConfigOk: "addConfigOk",
Expand Down
3 changes: 2 additions & 1 deletion Extension/ui/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@
<tr>
<!-- select configuration name -->
<td>
<div class="select-editable" style="width: 300px; margin-right: 10px">
<div class="select-editable" style="width: 300px; margin-left: -3px; margin-right: 7px">
<select id="configSelection" style="width: 300px"></select>
<input id=configName style="width: 267px" type="text"/>
</div>
Expand All @@ -473,6 +473,7 @@
</td>
</tr>
</table>
<div id="configNameInvalid" class="error" style="width: 290px"></div>
</div>
</div>

Expand Down
2 changes: 2 additions & 0 deletions Extension/ui/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
const elementId: { [key: string]: string } = {
// Basic settings
configName: "configName",
configNameInvalid: "configNameInvalid",
configSelection: "configSelection",
addConfigDiv: "addConfigDiv",
addConfigBtn: "addConfigBtn",
Expand Down Expand Up @@ -285,6 +286,7 @@ class SettingsApp {
private updateErrors(errors: any): void {
this.updating = true;
try {
this.showErrorWithInfo(elementId.configNameInvalid, errors.name);
this.showErrorWithInfo(elementId.intelliSenseModeInvalid, errors.intelliSenseMode);
this.showErrorWithInfo(elementId.compilerPathInvalid, errors.compilerPath);
this.showErrorWithInfo(elementId.includePathInvalid, errors.includePath);
Expand Down

0 comments on commit 1145a49

Please sign in to comment.