Skip to content

Commit 3f3facd

Browse files
committed
Warn when starting debugging with no Mains available
1 parent b3f055d commit 3f3facd

File tree

3 files changed

+117
-101
lines changed

3 files changed

+117
-101
lines changed

integration/vscode/ada/src/debugConfigProvider.ts

Lines changed: 108 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1+
import assert from 'assert';
12
import * as path from 'path';
23
import * as vscode from 'vscode';
3-
import { ContextClients } from './clients';
4-
import { getExecutables, getMains } from './helpers';
5-
import assert from 'assert';
6-
import { exec } from 'child_process';
4+
import { contextClients } from './extension';
5+
import { getExecutables, getMains, getProjectFile } from './helpers';
76

87
/**
98
* Ada Configuration for a debug session
@@ -23,14 +22,14 @@ interface AdaConfig extends vscode.DebugConfiguration {
2322
}
2423

2524
/**
26-
* Initialize debugging on an ada project by creating a default configuration in launch.json
27-
* @param ctx - the ada extension context
28-
* @param clients - the language clients
25+
* Initialize debugging support for Ada projects.
26+
*
27+
* @param ctx - the Ada extension context
2928
* @returns the debug configuration provider
3029
*/
31-
export function initializeDebugging(ctx: vscode.ExtensionContext, clients: ContextClients) {
30+
export function initializeDebugging(ctx: vscode.ExtensionContext) {
3231
// Instantiate a DebugConfigProvider for Ada and register it.
33-
const provider = new AdaDebugConfigProvider(clients);
32+
const provider = new AdaDebugConfigProvider();
3433

3534
// This provider is registered for the 'ada' debugger type. It means that
3635
// it is triggered either when a configuration with type 'ada' is launched,
@@ -55,7 +54,8 @@ export function initializeDebugging(ctx: vscode.ExtensionContext, clients: Conte
5554
/**
5655
* Initialize a debug configuration based on 'cppdbg' for the given executable
5756
* if specified. Otherwise the program field includes
58-
* ${command:ada.getOrAskForProgram} to prompt the User for an executable to debug.
57+
* $\{command:ada.getOrAskForProgram\} to prompt the User for an executable to
58+
* debug.
5959
*
6060
* @param program - the executable to debug (optional)
6161
* @returns an AdaConfig
@@ -88,13 +88,8 @@ function initializeConfig(program?: string): AdaConfig {
8888
}
8989

9090
export class AdaDebugConfigProvider implements vscode.DebugConfigurationProvider {
91-
private readonly clients: ContextClients;
9291
public static adaConfigType = 'cppdbg';
9392

94-
constructor(clients: ContextClients) {
95-
this.clients = clients;
96-
}
97-
9893
async provideDebugConfigurations(
9994
folder: vscode.WorkspaceFolder | undefined,
10095
_token?: vscode.CancellationToken | undefined
@@ -110,36 +105,42 @@ export class AdaDebugConfigProvider implements vscode.DebugConfigurationProvider
110105

111106
if (folder != undefined) {
112107
// Offer a list of known Mains from the project
113-
const mains = await getMains(this.clients.adaClient);
114-
const execs = await getExecutables(this.clients.adaClient);
108+
const mains = await getMains(contextClients.adaClient);
109+
const execs = await getExecutables(contextClients.adaClient);
115110
assert(
116111
execs.length == mains.length,
117112
`The ALS returned mains.length = ${mains.length} and ` +
118113
`execs.length = ${execs.length}` +
119114
`when they should be equal`
120115
);
121-
const quickpick = [];
122-
for (let i = 0; i < mains.length; i++) {
123-
const exec = execs[i];
124-
const main = mains[i];
125-
quickpick.push({
126-
label: vscode.workspace.asRelativePath(main),
127-
description: 'Generate the associated launch configuration',
128-
execPath: vscode.workspace.asRelativePath(exec),
116+
117+
if (mains.length > 0) {
118+
const quickpick = [];
119+
for (let i = 0; i < mains.length; i++) {
120+
const exec = execs[i];
121+
const main = mains[i];
122+
quickpick.push({
123+
label: vscode.workspace.asRelativePath(main),
124+
description: 'Generate the associated launch configuration',
125+
execPath: vscode.workspace.asRelativePath(exec),
126+
});
127+
}
128+
const selectedProgram = await vscode.window.showQuickPick(quickpick, {
129+
placeHolder: 'Select a main to create a launch configuration',
129130
});
130-
}
131-
const selectedProgram = await vscode.window.showQuickPick(quickpick, {
132-
placeHolder: 'Select a main to create a launch configuration',
133-
});
134-
if (selectedProgram) {
135-
// The cppdbg debug configuration exepects the executable to be
136-
// a full path rather than a path relative to the specified
137-
// cwd. That is why we include ${workspaceFolder}.
138-
const configuration = initializeConfig(
139-
`\${workspaceFolder}/${selectedProgram.execPath}`
140-
);
141-
configs.push(configuration);
131+
if (selectedProgram) {
132+
// The cppdbg debug configuration exepects the executable to be
133+
// a full path rather than a path relative to the specified
134+
// cwd. That is why we include ${workspaceFolder}.
135+
const configuration = initializeConfig(
136+
`\${workspaceFolder}/${selectedProgram.execPath}`
137+
);
138+
configs.push(configuration);
139+
} else {
140+
return Promise.reject('Cancelled');
141+
}
142142
} else {
143+
void warnAboutNoMains();
143144
return Promise.reject('Cancelled');
144145
}
145146
}
@@ -171,56 +172,79 @@ export class AdaDebugConfigProvider implements vscode.DebugConfigurationProvider
171172
return debugConfiguration;
172173
}
173174

174-
const exec = await this.getOrAskForProgram();
175+
const exec = await getOrAskForProgram();
175176

176177
if (exec) {
177178
return initializeConfig(`\${workspaceFolder}/${exec}`);
178179
}
179180

180181
return undefined;
181182
}
183+
}
182184

183-
/**
184-
* Get an executable based on the project and the current open file.
185-
*
186-
* If the project only defines one main, it is returned immediately.
187-
*
188-
* If the project defines multiple mains, and if the current open file
189-
* matches one of the mains, the corresponding executable is returned.
190-
*
191-
* Otherwise, the list of mains is offered to the user as a QuickPicker to
192-
* choose a main file. The executable corresponding to the selected main
193-
* file is returned.
194-
*
195-
* Note that paths are returned relative to the workspace.
196-
*
197-
* @returns the path of the executable to debug *relative to the workspace*,
198-
* or *undefined* if no selection was made.
199-
*/
200-
async getOrAskForProgram(): Promise<string | undefined> {
201-
const mains = await getMains(this.clients.adaClient);
202-
const execs = await getExecutables(this.clients.adaClient);
185+
/**
186+
* GDB default setup options
187+
*/
188+
const setupCmd = [
189+
{
190+
description: 'Catch all Ada exceptions',
191+
text: 'catch exception',
192+
ignoreFailures: true,
193+
},
194+
{
195+
description: 'Enable pretty-printing for gdb',
196+
text: '-enable-pretty-printing',
197+
ignoreFailures: true,
198+
},
199+
{
200+
description: 'Set Disassembly Flavor to Intel',
201+
text: '-gdb-set disassembly-flavor intel',
202+
ignoreFailures: true,
203+
},
204+
];
203205

204-
assert(
205-
execs.length == mains.length,
206-
`The ALS returned mains.length = ${mains.length} and ` +
207-
`execs.length = ${execs.length}` +
208-
`when they should be equal`
209-
);
206+
/**
207+
* Get an executable based on the project and the current open file.
208+
*
209+
* If the project only defines one main, it is returned immediately.
210+
*
211+
* If the project defines multiple mains, and if the current open file
212+
* matches one of the mains, the corresponding executable is returned.
213+
*
214+
* Otherwise, the list of mains is offered to the user as a QuickPicker to
215+
* choose a main file. The executable corresponding to the selected main
216+
* file is returned.
217+
*
218+
* Note that paths are returned relative to the workspace.
219+
*
220+
* @returns the path of the executable to debug *relative to the workspace*,
221+
* or *undefined* if no selection was made.
222+
*/
223+
async function getOrAskForProgram(): Promise<string | undefined> {
224+
const mains = await getMains(contextClients.adaClient);
225+
const execs = await getExecutables(contextClients.adaClient);
210226

211-
if (execs.length == 1) return vscode.workspace.asRelativePath(execs[0]);
227+
assert(
228+
execs.length == mains.length,
229+
`The ALS returned mains.length = ${mains.length} and ` +
230+
`execs.length = ${execs.length}` +
231+
`when they should be equal`
232+
);
212233

213-
// Check if the current file matches one of the mains of the project. If
214-
// so, use it.
215-
const file = vscode.window.activeTextEditor?.document.uri.path;
216-
if (file != undefined) {
217-
for (let i = 0; i < mains.length; i++) {
218-
if (file == mains[i]) {
219-
return vscode.workspace.asRelativePath(execs[i]);
220-
}
234+
if (execs.length == 1) return vscode.workspace.asRelativePath(execs[0]);
235+
236+
// Check if the current file matches one of the mains of the project. If
237+
// so, use it.
238+
const file = vscode.window.activeTextEditor?.document.uri.path;
239+
if (file != undefined) {
240+
for (let i = 0; i < mains.length; i++) {
241+
if (file == mains[i]) {
242+
return vscode.workspace.asRelativePath(execs[i]);
221243
}
222244
}
245+
}
223246

247+
if (mains.length > 0) {
224248
// There is no current file or it matches no known Main of the project,
225249
// so we offer all Mains in a QuickPicker for the user to choose from.
226250
const quickpick = [];
@@ -239,28 +263,16 @@ export class AdaDebugConfigProvider implements vscode.DebugConfigurationProvider
239263
if (selectedProgram) {
240264
return selectedProgram.execRelPath;
241265
}
242-
243-
return undefined;
266+
} else {
267+
void warnAboutNoMains();
244268
}
245-
}
246269

247-
/**
248-
* GDB default setup options
249-
*/
250-
const setupCmd = [
251-
{
252-
description: 'Catch all Ada exceptions',
253-
text: 'catch exception',
254-
ignoreFailures: true,
255-
},
256-
{
257-
description: 'Enable pretty-printing for gdb',
258-
text: '-enable-pretty-printing',
259-
ignoreFailures: true,
260-
},
261-
{
262-
description: 'Set Disassembly Flavor to Intel',
263-
text: '-gdb-set disassembly-flavor intel',
264-
ignoreFailures: true,
265-
},
266-
];
270+
return undefined;
271+
}
272+
async function warnAboutNoMains() {
273+
void vscode.window.showWarningMessage(
274+
`Your Ada project file '${await getProjectFile(
275+
contextClients.adaClient
276+
)}' does not define a 'Main' attribute. ` + 'Debugging is not possible without it.'
277+
);
278+
}

integration/vscode/ada/src/extension.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
7878

7979
await Promise.all([contextClients.adaClient.onReady(), contextClients.gprClient.onReady()]);
8080

81-
const adaDebugConfigProvider = initializeDebugging(context, contextClients);
81+
const adaDebugConfigProvider = initializeDebugging(context);
8282

8383
registerCommands(context, contextClients, adaDebugConfigProvider);
8484

integration/vscode/ada/src/helpers.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -198,14 +198,18 @@ type ExecutablesResponse = {
198198
};
199199

200200
/**
201-
* Get the project file from the configuration or if not, the language server
201+
* Get the project file from the workspace configuration if available, or from
202+
* the ALS if not.
203+
*
202204
* @param client - the client to send the request to
203205
* @returns a string contains the path of the project file
204206
*/
205207
export async function getProjectFile(client: LanguageClient): Promise<string> {
206-
const config: string | undefined = vscode.workspace.getConfiguration('ada').get('projectFile');
207-
if (config != undefined && config != '') {
208-
return config;
208+
const configValue: string | undefined = vscode.workspace
209+
.getConfiguration('ada')
210+
.get('projectFile');
211+
if (configValue != undefined && configValue != '') {
212+
return configValue;
209213
} else {
210214
const result: ProjectFileResponse = await client.sendRequest('$/glsProjectFile');
211215
return result.projectFile;

0 commit comments

Comments
 (0)