Skip to content

Commit 91380b3

Browse files
author
Elaheh Rashedi
authored
add "add configuration" feature (ready) (#9226)
1 parent f0d43ce commit 91380b3

File tree

7 files changed

+150
-46
lines changed

7 files changed

+150
-46
lines changed

Extension/package.json

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@
5050
"onLanguage:cuda-cpp",
5151
"onCommand:extension.pickNativeProcess",
5252
"onCommand:extension.pickRemoteNativeProcess",
53-
"onCommand:C_Cpp.BuildAndDebugActiveFile",
5453
"onCommand:C_Cpp.RestartIntelliSenseForFile",
5554
"onCommand:C_Cpp.ConfigurationEditJSON",
5655
"onCommand:C_Cpp.ConfigurationEditUI",
@@ -2752,6 +2751,12 @@
27522751
"title": "%c_cpp.command.BuildAndRunFile.title%",
27532752
"category": "C/C++",
27542753
"icon": "$(run)"
2754+
},
2755+
{
2756+
"command": "C_Cpp.AddDebugConfiguration",
2757+
"title": "%c_cpp.command.AddDebugConfiguration.title%",
2758+
"category": "C/C++",
2759+
"icon": "$(debug-configure)"
27552760
}
27562761
],
27572762
"keybindings": [
@@ -3883,31 +3888,43 @@
38833888
"group": "navigation@1"
38843889
}
38853890
],
3891+
"editor/title": [
3892+
{
3893+
"command": "C_Cpp.AddDebugConfiguration",
3894+
"when": "editorLangId == 'c' && config.C_Cpp.debugShortcut && BuildAndDebug.isSourceFile && BuildAndDebug.isFolderOpen || editorLangId == 'cpp' && config.C_Cpp.debugShortcut && BuildAndDebug.isSourceFile && BuildAndDebug.isFolderOpen || editorLangId == 'cuda-cpp' && config.C_Cpp.debugShortcut && BuildAndDebug.isSourceFile && BuildAndDebug.isFolderOpen",
3895+
"group": "navigation"
3896+
}
3897+
],
38863898
"editor/context": [
38873899
{
38883900
"when": "editorLangId == 'c' || editorLangId == 'cpp' || editorLangId == 'cuda-cpp'",
38893901
"command": "C_Cpp.SwitchHeaderSource",
3890-
"group": "other1_navigation@1"
3902+
"group": "custom1@1"
38913903
},
38923904
{
38933905
"when": "editorLangId == 'c' || editorLangId == 'cpp' || editorLangId == 'cuda-cpp'",
38943906
"command": "workbench.action.gotoSymbol",
3895-
"group": "other1_navigation@3"
3907+
"group": "custom1@2"
38963908
},
38973909
{
38983910
"when": "editorLangId == 'c' || editorLangId == 'cpp' || editorLangId == 'cuda-cpp'",
38993911
"command": "workbench.action.showAllSymbols",
3900-
"group": "other1_navigation@4"
3912+
"group": "custom1@3"
39013913
},
39023914
{
3903-
"when": "editorLangId == 'c' || editorLangId == 'cpp' || editorLangId == 'cuda-cpp'",
39043915
"command": "C_Cpp.RunCodeAnalysisOnActiveFile",
3905-
"group": "other2@2"
3916+
"when": "editorLangId == 'c' || editorLangId == 'cpp' || editorLangId == 'cuda-cpp'",
3917+
"group": "custom2@1"
39063918
},
39073919
{
3908-
"when": "editorLangId == 'c' || editorLangId == 'cpp' || editorLangId == 'cuda-cpp'",
39093920
"command": "C_Cpp.RestartIntelliSenseForFile",
3910-
"group": "other2@3"
3921+
"when": "editorLangId == 'c' || editorLangId == 'cpp' || editorLangId == 'cuda-cpp'",
3922+
"group": "custom2@2"
3923+
},
3924+
{
3925+
"command": "C_Cpp.AddDebugConfiguration",
3926+
"when": "editorLangId == 'c' && config.C_Cpp.debugShortcut && BuildAndDebug.isSourceFile && BuildAndDebug.isFolderOpen || editorLangId == 'cpp' && config.C_Cpp.debugShortcut && BuildAndDebug.isSourceFile && BuildAndDebug.isFolderOpen || editorLangId == 'cuda-cpp' && config.C_Cpp.debugShortcut && BuildAndDebug.isSourceFile && BuildAndDebug.isFolderOpen",
3927+
"group": "custom2@3"
39113928
}
39123929
],
39133930
"commandPalette": [

Extension/package.nls.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"c_cpp.command.ClearCodeAnalysisSquiggles.title": "Clear Code Analysis Squiggles",
2828
"c_cpp.command.BuildAndDebugFile.title": "Debug C/C++ File",
2929
"c_cpp.command.BuildAndRunFile.title": "Run C/C++ File",
30+
"c_cpp.command.AddDebugConfiguration.title": "Add Debug Configuration",
3031
"c_cpp.configuration.maxConcurrentThreads.markdownDescription": { "message": "The maximum number of concurrent threads to use for language service processing. The value is a hint and may not always be used. The default of `null` (empty) uses the number of logical processors available.", "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." ] },
3132
"c_cpp.configuration.maxCachedProcesses.markdownDescription": { "message": "The maximum number of cached processes to use for language service processing. The default of `null` (empty) uses twice the number of logical processors available.", "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." ] },
3233
"c_cpp.configuration.maxMemory.markdownDescription": { "message": "The maximum memory (in MB) available for language service processing. Fewer processes will be cached and run concurrently after this memory usage is exceeded. The default of `null` (empty) uses the system's free memory.", "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." ] },

Extension/src/Debugger/configurationProvider.ts

Lines changed: 88 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ import * as Telemetry from '../telemetry';
1414
import * as logger from '../logger';
1515
import * as nls from 'vscode-nls';
1616
import { IConfiguration, IConfigurationSnippet, DebuggerType, DebuggerEvent, MIConfigurations, WindowsConfigurations, WSLConfigurations, PipeTransportConfigurations } from './configurations';
17-
import { parse } from 'comment-json';
17+
import * as jsonc from 'comment-json';
1818
import { PlatformInformation } from '../platform';
1919
import { Environment, ParsedEnvironmentFile } from './ParsedEnvironmentFile';
20-
import { CppSettings } from '../LanguageServer/settings';
20+
import { CppSettings, OtherSettings } from '../LanguageServer/settings';
2121
import { configPrefix } from '../LanguageServer/extension';
2222

2323
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
@@ -593,13 +593,93 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
593593
return false;
594594
}
595595

596+
private getLaunchJsonPath(): string | undefined {
597+
return util.getJsonPath("launch.json");
598+
}
599+
600+
public getRawLaunchJson(): Promise<any> {
601+
const path: string | undefined = this.getLaunchJsonPath();
602+
return util.getRawJson(path);
603+
}
604+
605+
public async writeDebugConfig(config: vscode.DebugConfiguration, folder?: vscode.WorkspaceFolder): Promise<void> {
606+
const launchJsonPath: string | undefined = this.getLaunchJsonPath();
607+
608+
if (this.checkDebugConfigExists(config.name, folder)) {
609+
if (launchJsonPath) {
610+
const doc: vscode.TextDocument = await vscode.workspace.openTextDocument(launchJsonPath);
611+
if (doc) {
612+
vscode.window.showTextDocument(doc);
613+
}
614+
}
615+
return;
616+
}
617+
const rawLaunchJson: any = await this.getRawLaunchJson();
618+
if (!rawLaunchJson.configurations) {
619+
rawLaunchJson.configurations = new Array();
620+
}
621+
if (!rawLaunchJson.version) {
622+
rawLaunchJson.version = "2.0.0";
623+
}
624+
625+
config.detail = undefined;
626+
config.existing = undefined;
627+
config.isDefault = undefined;
628+
rawLaunchJson.configurations.push(config);
629+
630+
if (!launchJsonPath) {
631+
throw new Error("Failed to get tasksJsonPath in checkBuildTaskExists()");
632+
}
633+
634+
const settings: OtherSettings = new OtherSettings();
635+
await util.writeFileText(launchJsonPath, jsonc.stringify(rawLaunchJson, null, settings.editorTabSize));
636+
await vscode.workspace.openTextDocument(launchJsonPath);
637+
const doc: vscode.TextDocument = await vscode.workspace.openTextDocument(launchJsonPath);
638+
if (doc) {
639+
vscode.window.showTextDocument(doc);
640+
}
641+
}
642+
643+
public async addDebugConfiguration(textEditor: vscode.TextEditor): Promise<void> {
644+
const folder: vscode.WorkspaceFolder | undefined = vscode.workspace.getWorkspaceFolder(textEditor.document.uri);
645+
if (!folder) {
646+
return;
647+
}
648+
const selectedConfig: vscode.DebugConfiguration | undefined = await this.selectConfiguration(textEditor, true);
649+
if (!selectedConfig) {
650+
Telemetry.logDebuggerEvent(DebuggerEvent.launchPlayButton, { "debugType": "AddConfigurationOnly", "folderMode": folder ? "folder" : "singleFile", "cancelled": "true" });
651+
return; // User canceled it.
652+
}
653+
654+
// Write preLaunchTask into tasks.json file.
655+
if (selectedConfig.preLaunchTask) {
656+
await cppBuildTaskProvider.writeBuildTask(selectedConfig.preLaunchTask);
657+
}
658+
// Write debug configuraion in launch.json file.
659+
await this.writeDebugConfig(selectedConfig, folder);
660+
661+
}
662+
596663
public async buildAndRun(textEditor: vscode.TextEditor): Promise<void> {
597664
// Turn off the debug mode.
598665
return this.buildAndDebug(textEditor, false);
599666
}
600667

601668
public async buildAndDebug(textEditor: vscode.TextEditor, debugModeOn: boolean = true): Promise<void> {
669+
const folder: vscode.WorkspaceFolder | undefined = vscode.workspace.getWorkspaceFolder(textEditor.document.uri);
670+
const selectedConfig: vscode.DebugConfiguration | undefined = await this.selectConfiguration(textEditor, true);
671+
if (!selectedConfig) {
672+
Telemetry.logDebuggerEvent(DebuggerEvent.launchPlayButton, { "debugType": debugModeOn ? "debug" : "run", "folderMode": folder ? "folder" : "singleFile", "cancelled": "true" });
673+
return; // User canceled it.
674+
}
675+
676+
// Keep track of the entry point where the debug has been selected, for telemetry purposes.
677+
selectedConfig.debuggerEvent = DebuggerEvent.launchPlayButton;
678+
// startDebugging will trigger a call to resolveDebugConfiguration.
679+
await vscode.debug.startDebugging(folder, selectedConfig, {noDebug: !debugModeOn});
680+
}
602681

682+
private async selectConfiguration(textEditor: vscode.TextEditor, pickDefault: boolean = false): Promise<vscode.DebugConfiguration | undefined> {
603683
const folder: vscode.WorkspaceFolder | undefined = vscode.workspace.getWorkspaceFolder(textEditor.document.uri);
604684
if (!util.isCppOrCFile(textEditor.document.uri)) {
605685
vscode.window.showErrorMessage(localize("cannot.build.non.cpp", 'Cannot build and debug because the active file is not a C or C++ source file.'));
@@ -612,14 +692,14 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
612692
configs = configs.concat(await this.provideDebugConfigurationsForType(DebuggerType.cppvsdbg, folder));
613693
}
614694

615-
const defaultConfig: vscode.DebugConfiguration[] = findDefaultConfig(configs);
695+
const defaultConfig: vscode.DebugConfiguration[] | undefined = pickDefault ? findDefaultConfig(configs) : undefined;
616696

617697
const items: MenuItem[] = configs.map<MenuItem>(config => ({ label: config.name, configuration: config, description: config.detail, detail: config.existing }));
618698

619699
let selection: MenuItem | undefined;
620700

621701
// if there was only one config for the default task, choose that config, otherwise ask the user to choose.
622-
if (defaultConfig.length === 1) {
702+
if (defaultConfig && defaultConfig.length === 1) {
623703
selection = { label: defaultConfig[0].name, configuration: defaultConfig[0], description: defaultConfig[0].detail, detail: defaultConfig[0].existing };
624704
} else {
625705
let sortedItems: MenuItem[] = [];
@@ -636,21 +716,10 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
636716
placeHolder: (items.length === 0 ? localize("no.compiler.found", "No compiler found") : localize("select.debug.configuration", "Select a debug configuration"))
637717
});
638718
}
639-
640-
if (!selection) {
641-
Telemetry.logDebuggerEvent(DebuggerEvent.launchPlayButton, { "debugType": debugModeOn ? "debug" : "run", "folderMode": folder ? "folder" : "singleFile", "cancelled": "true" });
642-
return; // User canceled it.
643-
}
644-
645-
if (this.isClConfiguration(selection.label) && this.showErrorIfClNotAvailable(selection.label)) {
719+
if (selection && this.isClConfiguration(selection.configuration.name) && this.showErrorIfClNotAvailable(selection.configuration.name)) {
646720
return;
647721
}
648-
649-
// Keep track of the entry point where the debug has been selected, for telemetry purposes.
650-
selection.configuration.debuggerEvent = DebuggerEvent.launchPlayButton;
651-
// startDebugging will trigger a call to resolveDebugConfiguration.
652-
await vscode.debug.startDebugging(folder, selection.configuration, {noDebug: !debugModeOn});
653-
722+
return selection?.configuration;
654723
}
655724

656725
private async resolvePreLaunchTask(folder: vscode.WorkspaceFolder | undefined, configuration: vscode.DebugConfiguration, debugModeOn: boolean = true): Promise<void> {
@@ -662,7 +731,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
662731
if (configuration.preLaunchTask) {
663732
try {
664733
if (folder) {
665-
await cppBuildTaskProvider.checkBuildTaskExists(configuration.preLaunchTask);
734+
await cppBuildTaskProvider.writeBuildTask(configuration.preLaunchTask);
666735
} else {
667736
// In case of singleFile, remove the preLaunch task from the debug configuration and run it here instead.
668737
await cppBuildTaskProvider.runBuildTask(configuration.preLaunchTask);
@@ -832,7 +901,7 @@ export class ConfigurationSnippetProvider implements vscode.CompletionItemProvid
832901
public provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext): Thenable<vscode.CompletionList> {
833902
let items: vscode.CompletionItem[] = this.snippets;
834903

835-
const launch: any = parse(document.getText());
904+
const launch: any = jsonc.parse(document.getText());
836905
// Check to see if the array is empty, so any additional inserted snippets will need commas.
837906
if (launch.configurations.length !== 0) {
838907
items = [];

Extension/src/Debugger/extension.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@ import { NativeAttachItemsProviderFactory } from './nativeAttach';
1010
import { DebugConfigurationProvider, ConfigurationAssetProviderFactory, ConfigurationSnippetProvider, IConfigurationAssetProvider } from './configurationProvider';
1111
import { CppdbgDebugAdapterDescriptorFactory, CppvsdbgDebugAdapterDescriptorFactory } from './debugAdapterDescriptorFactory';
1212
import { DebuggerType } from './configurations';
13+
import * as nls from 'vscode-nls';
1314

1415
// The extension deactivate method is asynchronous, so we handle the disposables ourselves instead of using extensonContext.subscriptions.
1516
const disposables: vscode.Disposable[] = [];
17+
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
1618

1719
export async function initialize(context: vscode.ExtensionContext): Promise<void> {
1820
// Activate Process Picker Commands
@@ -39,6 +41,13 @@ export async function initialize(context: vscode.ExtensionContext): Promise<void
3941
const debugProvider: DebugConfigurationProvider = new DebugConfigurationProvider(assetProvider, DebuggerType.all);
4042
disposables.push(vscode.commands.registerTextEditorCommand("C_Cpp.BuildAndDebugFile", async (textEditor: vscode.TextEditor, edit: vscode.TextEditorEdit, ...args: any[]) => { await debugProvider.buildAndDebug(textEditor); }));
4143
disposables.push(vscode.commands.registerTextEditorCommand("C_Cpp.BuildAndRunFile", async (textEditor: vscode.TextEditor, edit: vscode.TextEditorEdit, ...args: any[]) => { await debugProvider.buildAndRun(textEditor); }));
44+
disposables.push(vscode.commands.registerTextEditorCommand("C_Cpp.AddDebugConfiguration", async (textEditor: vscode.TextEditor, edit: vscode.TextEditorEdit, ...args: any[]) => {
45+
const folder: vscode.WorkspaceFolder | undefined = vscode.workspace.getWorkspaceFolder(textEditor.document.uri);
46+
if (!folder) {
47+
vscode.window.showWarningMessage(localize("add.debug.configuration.not.available.for.single.file", "Add debug configuration is not available for single file."));
48+
}
49+
await debugProvider.addDebugConfiguration(textEditor);
50+
}));
4251

4352
assetProvider.getConfigurationSnippets();
4453

Extension/src/LanguageServer/client.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1730,6 +1730,7 @@ export class DefaultClient implements Client {
17301730
const uri: string = document.uri.toString();
17311731
openFileVersions.set(uri, document.version);
17321732
vscode.commands.executeCommand('setContext', 'BuildAndDebug.isSourceFile', util.isCppOrCFile(document.uri));
1733+
vscode.commands.executeCommand('setContext', 'BuildAndDebug.isFolderOpen', util.isFolderOpen(document.uri));
17331734
} else {
17341735
vscode.commands.executeCommand('setContext', 'BuildAndDebug.isSourceFile', false);
17351736
}
@@ -2668,6 +2669,7 @@ export class DefaultClient implements Client {
26682669
|| editor.document.languageId === "cpp"
26692670
|| editor.document.languageId === "cuda-cpp")) {
26702671
vscode.commands.executeCommand('setContext', 'BuildAndDebug.isSourceFile', util.isCppOrCFile(editor.document.uri));
2672+
vscode.commands.executeCommand('setContext', 'BuildAndDebug.isFolderOpen', util.isFolderOpen(editor.document.uri));
26712673
// If using vcFormat, check for a ".editorconfig" file, and apply those text options to the active document.
26722674
const settings: CppSettings = new CppSettings(this.RootUri);
26732675
if (settings.useVcFormat(editor.document)) {

0 commit comments

Comments
 (0)