Skip to content

Commit 8703c3c

Browse files
Merge branch 'topic/run-main-root' into 'master'
Fix vscode run main task when executable is at workspace root See merge request eng/ide/ada_language_server!1703
2 parents 41043c3 + 73f3508 commit 8703c3c

File tree

7 files changed

+105
-70
lines changed

7 files changed

+105
-70
lines changed

integration/vscode/ada/src/taskProviders.ts

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
----------------------------------------------------------------------------*/
1717

1818
import assert from 'assert';
19-
import { basename } from 'path';
19+
import path, { basename } from 'path';
2020
import * as vscode from 'vscode';
2121
import { CMD_GPR_PROJECT_ARGS } from './commands';
2222
import { adaExtState, logger } from './extension';
@@ -366,7 +366,10 @@ const predefinedTasks: PredefinedTask[] = [
366366
* both 'ada' and 'spark' tasks.
367367
*/
368368
export class SimpleTaskProvider implements vscode.TaskProvider {
369-
constructor(public taskType: string, private taskDecls: PredefinedTask[]) {}
369+
constructor(
370+
public taskType: string,
371+
private taskDecls: PredefinedTask[],
372+
) {}
370373

371374
async provideTasks(token?: vscode.CancellationToken): Promise<vscode.Task[]> {
372375
if (token?.isCancellationRequested) {
@@ -406,11 +409,19 @@ export class SimpleTaskProvider implements vscode.TaskProvider {
406409
taskGroup: vscode.TaskGroup.Build,
407410
};
408411

412+
let execPath = main.execRelPath();
413+
/**
414+
* If the exec is directly at the root of the workspace,
415+
* prepend ./ to make it possible for shells to execute it.
416+
*/
417+
if (!execPath.includes(path.sep)) {
418+
execPath = './' + execPath;
419+
}
409420
const runTask: PredefinedTask = {
410421
label: getRunTaskPlainName(main),
411422
taskDef: {
412423
type: this.taskType,
413-
command: main.execRelPath(),
424+
command: execPath,
414425
args: [],
415426
},
416427
};
@@ -425,7 +436,7 @@ export class SimpleTaskProvider implements vscode.TaskProvider {
425436
};
426437

427438
return [buildTask, runTask, buildAndRunTask];
428-
})
439+
}),
429440
);
430441
}
431442

@@ -453,7 +464,7 @@ export class SimpleTaskProvider implements vscode.TaskProvider {
453464
tDecl.label,
454465
tDecl.taskDef.type,
455466
undefined,
456-
tDecl.problemMatchers
467+
tDecl.problemMatchers,
457468
);
458469

459470
/**
@@ -483,7 +494,7 @@ export class SimpleTaskProvider implements vscode.TaskProvider {
483494

484495
async resolveTask(
485496
task: vscode.Task,
486-
token?: vscode.CancellationToken
497+
token?: vscode.CancellationToken,
487498
): Promise<vscode.Task | undefined> {
488499
/**
489500
* Note that this method is never called for tasks created by the
@@ -525,9 +536,8 @@ export class SimpleTaskProvider implements vscode.TaskProvider {
525536
*/
526537
const args = taskDef.args ?? [];
527538
try {
528-
const evaluatedArgs: (string | vscode.ShellQuotedString)[] = await evaluateArgs(
529-
args
530-
);
539+
const evaluatedArgs: (string | vscode.ShellQuotedString)[] =
540+
await evaluateArgs(args);
531541
execution = new vscode.ShellExecution(taskDef.command, evaluatedArgs);
532542
} catch (err) {
533543
let msg = 'Error while evaluating task arguments.';
@@ -547,7 +557,7 @@ export class SimpleTaskProvider implements vscode.TaskProvider {
547557
task.name,
548558
task.source,
549559
execution,
550-
task.problemMatchers
560+
task.problemMatchers,
551561
);
552562
}
553563

@@ -622,12 +632,12 @@ async function useAlire() {
622632
*/
623633
async function evaluateArgs(args: (string | vscode.ShellQuotedString)[]) {
624634
const commandRegex = new RegExp(
625-
`^\\\${command:\\s*((${TASK_TYPE_ADA}|${TASK_TYPE_SPARK})\\.[^}]*)\\s*}$`
635+
`^\\\${command:\\s*((${TASK_TYPE_ADA}|${TASK_TYPE_SPARK})\\.[^}]*)\\s*}$`,
626636
);
627637
const evaluatedArgs: (string | vscode.ShellQuotedString)[] = (
628638
await Promise.all(
629639
args.flatMap(async function (
630-
a: string | vscode.ShellQuotedString
640+
a: string | vscode.ShellQuotedString,
631641
): Promise<(string | vscode.ShellQuotedString)[]> {
632642
if (typeof a == 'string') {
633643
/**
@@ -667,7 +677,7 @@ async function evaluateArgs(args: (string | vscode.ShellQuotedString)[]) {
667677
}
668678

669679
return [a];
670-
})
680+
}),
671681
)
672682
).flat();
673683
return evaluatedArgs;
@@ -742,14 +752,14 @@ export function getBuildAndRunTaskName(main?: AdaMain) {
742752
export function createSparkTaskProvider(): SimpleTaskProvider {
743753
return new SimpleTaskProvider(
744754
TASK_TYPE_SPARK,
745-
predefinedTasks.filter((v) => v.taskDef.type == TASK_TYPE_SPARK)
755+
predefinedTasks.filter((v) => v.taskDef.type == TASK_TYPE_SPARK),
746756
);
747757
}
748758

749759
export function createAdaTaskProvider(): SimpleTaskProvider {
750760
return new SimpleTaskProvider(
751761
TASK_TYPE_ADA,
752-
predefinedTasks.filter((v) => v.taskDef.type == TASK_TYPE_ADA)
762+
predefinedTasks.filter((v) => v.taskDef.type == TASK_TYPE_ADA),
753763
);
754764
}
755765

@@ -849,7 +859,7 @@ abstract class SequentialExecution extends vscode.CustomExecution {
849859
} finally {
850860
closeEmitter.fire(2);
851861
}
852-
}
862+
},
853863
);
854864
},
855865
close() {
@@ -883,7 +893,7 @@ abstract class SequentialExecution extends vscode.CustomExecution {
883893
*/
884894
export async function findTaskByName(
885895
taskName: string,
886-
tasks?: vscode.Task[]
896+
tasks?: vscode.Task[],
887897
): Promise<vscode.Task> {
888898
if (!tasks) {
889899
tasks = (
@@ -921,7 +931,10 @@ export async function findTaskByName(
921931
* of the tasks to run are given at construction.
922932
*/
923933
class SequentialExecutionByName extends SequentialExecution {
924-
constructor(private taskName: string, private taskNames: string[]) {
934+
constructor(
935+
private taskName: string,
936+
private taskNames: string[],
937+
) {
925938
super();
926939
}
927940

@@ -941,7 +954,7 @@ class SequentialExecutionByName extends SequentialExecution {
941954
*/
942955
function runTaskSequence(
943956
tasks: vscode.Task[],
944-
writeEmitter: vscode.EventEmitter<string>
957+
writeEmitter: vscode.EventEmitter<string>,
945958
): Promise<number> {
946959
let p = new Promise<number>((resolve) => resolve(0));
947960
for (const t of tasks) {
@@ -996,15 +1009,15 @@ export async function getBuildAndRunTasks(): Promise<vscode.Task[]> {
9961009
.filter((t) => getConventionalTaskLabel(t).startsWith(getBuildAndRunTaskName()))
9971010

9981011
// Return workspace-defined tasks first
999-
.sort(workspaceTasksFirst)
1012+
.sort(workspaceTasksFirst),
10001013
);
10011014
}
10021015

10031016
export async function findBuildAndRunTask(adaMain: AdaMain): Promise<vscode.Task | undefined> {
10041017
return (await getBuildAndRunTasks()).find(
10051018
// Tasks defined in tasks.json will have a leading 'ada: ' while the
10061019
// ones auto-generated by the extension don't. We want to match both.
1007-
(t) => getConventionalTaskLabel(t) == getBuildAndRunTaskName(adaMain)
1020+
(t) => getConventionalTaskLabel(t) == getBuildAndRunTaskName(adaMain),
10081021
);
10091022
}
10101023

@@ -1039,15 +1052,15 @@ export async function getBuildMainTasks() {
10391052
tasks
10401053
.filter((t) => getConventionalTaskLabel(t).startsWith(getBuildTaskName()))
10411054
// Return workspace-defined tasks first
1042-
.sort(workspaceTasksFirst)
1055+
.sort(workspaceTasksFirst),
10431056
);
10441057
}
10451058

10461059
export async function findBuildMainTask(adaMain: AdaMain): Promise<vscode.Task | undefined> {
10471060
return (await getBuildMainTasks()).find(
10481061
// Tasks defined in tasks.json will have a leading 'ada: ' while the
10491062
// ones auto-generated by the extension don't. We want to match both.
1050-
(t) => getConventionalTaskLabel(t) == getBuildTaskName(adaMain)
1063+
(t) => getConventionalTaskLabel(t) == getBuildTaskName(adaMain),
10511064
);
10521065
}
10531066

integration/vscode/ada/test/suite/general/tasks.test.ts

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ ada: Run main - src/test.adb - obj/test${exe}
121121
const testAdbUri = vscode.Uri.joinPath(
122122
vscode.workspace.workspaceFolders[0].uri,
123123
'src',
124-
'test.adb'
124+
'test.adb',
125125
);
126126

127127
/**
@@ -134,7 +134,7 @@ ada: Run main - src/test.adb - obj/test${exe}
134134
(await getEnclosingSymbol(vscode.window.activeTextEditor, [vscode.SymbolKind.Function]))
135135
?.range,
136136
// The expected range is that of the inner-most subprogram P3
137-
new vscode.Range(13, 9, 18, 16)
137+
new vscode.Range(13, 9, 18, 16),
138138
);
139139
assert.equal(getSelectedRegion(vscode.window.activeTextEditor), '18:18');
140140

@@ -185,7 +185,7 @@ ada: Run main - src/test.adb - obj/test${exe}
185185
assert(resolved.execution);
186186
assert(
187187
isFromWorkspace(resolved),
188-
'Build task does not come from workspace. Source is: ' + resolved.source
188+
'Build task does not come from workspace. Source is: ' + resolved.source,
189189
);
190190

191191
const exec = buildTask.execution as vscode.ShellExecution;
@@ -215,7 +215,7 @@ ada: Run main - src/test.adb - obj/test${exe}
215215
obsoleteTaskDef,
216216
vscode.TaskScope.Workspace,
217217
'Obsolete Task',
218-
'Workspace'
218+
'Workspace',
219219
);
220220

221221
const prov = createAdaTaskProvider();
@@ -259,7 +259,7 @@ ada: Run main - src/test.adb - obj/test${exe}
259259
t,
260260
vscode.TaskScope.Workspace,
261261
'Invalid Task',
262-
'Workspace'
262+
'Workspace',
263263
);
264264

265265
/**
@@ -303,27 +303,46 @@ suite('Task Execution', function () {
303303

304304
/**
305305
* Check that the 'buildAndRunMain' task works fine with projects that
306-
* do not explicitly define an object directory.
306+
* produce the executable at the root of the workspace. In that case it is
307+
* necessary to use a leading `./` for the shell to be able to spawn the
308+
* executable.
307309
*/
308-
test('Build and run main task without object directory', async () => {
310+
test('Build and run main task when exec at workspace root', async () => {
309311
// Load a custom project that does not define any object dir by
310312
// changing the 'ada.projectFile' setting.
311313
const initialProjectFile = vscode.workspace.getConfiguration().get('ada.projectFile');
312314
try {
313315
await vscode.workspace
314316
.getConfiguration()
315-
.update(
316-
'ada.projectFile',
317-
'default_without_obj_dir' + path.sep + 'default_without_obj_dir.gpr'
318-
);
317+
.update('ada.projectFile', 'prj_exec_at_root' + path.sep + 'prj_exec_at_root.gpr');
318+
319319
/**
320320
* Wait a bit until the ALS loads the new project
321321
*/
322322
await new Promise((resolve) => setTimeout(resolve, 1000));
323+
324+
/**
325+
* Check that the task command starts with ./
326+
*/
327+
const runTask = (await vscode.tasks.fetchTasks({ type: 'ada' })).find((t) =>
328+
t.name.includes('Run main'),
329+
);
330+
assert(runTask?.execution instanceof vscode.ShellExecution);
331+
const cmdLine = getCmdLine(runTask.execution);
332+
assert(
333+
cmdLine.startsWith('.' + path.sep),
334+
`Task command doesn't start with './': ${cmdLine}`,
335+
);
336+
337+
/**
338+
* Check that the build and run task work.
339+
*/
340+
await testTask('Build main - src/main1.adb', testedTaskLabels, allProvidedTasks);
341+
await testTask('Run main - src/main1.adb', testedTaskLabels, allProvidedTasks);
323342
await testTask(
324343
'Build and run main - src/main1.adb',
325344
testedTaskLabels,
326-
allProvidedTasks
345+
allProvidedTasks,
327346
);
328347
} finally {
329348
// Reset the 'ada.projectFile' setting. If the previous value was
@@ -334,7 +353,7 @@ suite('Task Execution', function () {
334353
.getConfiguration()
335354
.update(
336355
'ada.projectFile',
337-
initialProjectFile === '' ? undefined : initialProjectFile
356+
initialProjectFile === '' ? undefined : initialProjectFile,
338357
);
339358
}
340359
});
@@ -409,7 +428,7 @@ async function openSrcFile() {
409428
const testAdbUri = vscode.Uri.joinPath(
410429
vscode.workspace.workspaceFolders[0].uri,
411430
'src',
412-
'test.adb'
431+
'test.adb',
413432
);
414433

415434
await vscode.window.showTextDocument(testAdbUri);

0 commit comments

Comments
 (0)