Skip to content

Commit 5fa261b

Browse files
Merge branch 'topic/#1520' into 'master'
Add testing and entry in CHANGELOG for status bar See merge request eng/ide/ada_language_server!1958
2 parents cf0aeae + 055af07 commit 5fa261b

File tree

11 files changed

+216
-13
lines changed

11 files changed

+216
-13
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ section below it for the last release. -->
77

88
* Fix a bug that caused the ALS to hang when trying to complete partially qualified invisible symbols
99
* Support loading a fresh checkout of an Alire crate by automatically performing the necessary Alire workspace initializations
10+
* VS Code status bar now displays an item showing the project-loading status and useful commands provided by the extension when hovering on it
1011

1112
## 26.0.202502240
1213

integration/vscode/ada/.vscode-test.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ if (process.env['MOCHA_GREP']) {
3939
baseMochaOptions.grep = process.env['MOCHA_GREP'];
4040
}
4141

42-
const testsuites = ['general', 'workspace_missing_dirs', 'dot-als-json'];
42+
const testsuites = ['general', 'workspace_missing_dirs', 'dot-als-json', 'status_bar'];
4343

4444
export default defineConfig(
4545
testsuites.map((suiteName) => {

integration/vscode/ada/src/ExtensionState.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ import {
2323
createSparkTaskProvider,
2424
} from './taskProviders';
2525
import { isAbsolute } from 'path';
26+
import {
27+
CMD_SHOW_EXTENSION_LOGS,
28+
CMD_SHOW_ADA_LS_OUTPUT,
29+
CMD_SHOW_GPR_LS_OUTPUT,
30+
CMD_RELOAD_PROJECT,
31+
CMD_RESTART_LANG_SERVERS,
32+
} from './commands';
2633

2734
/**
2835
* Return type of the 'als-source-dirs' LSP request.
@@ -268,18 +275,18 @@ export class ExtensionState {
268275
this.statusBar.tooltip.appendMarkdown('\n\n---\n\n');
269276
}
270277
this.statusBar.tooltip.appendMarkdown(
271-
`[$(terminal) Open Extension Logs](command:ada.showExtensionOutput
278+
`[$(terminal) Open Extension Logs](command:${CMD_SHOW_EXTENSION_LOGS}
272279
"Show Ada Extension Output")
273280
274-
[$(terminal) Open Logs for Ada & SPARK](command:ada.showAdaLSOutput
281+
[$(terminal) Open Logs for Ada & SPARK](command:${CMD_SHOW_ADA_LS_OUTPUT}
275282
"Show Ada Language Server for Ada & SPARK Output")
276283
277-
[$(terminal) Open Logs for GPR](command:ada.showGprLSOutput
284+
[$(terminal) Open Logs for GPR](command:${CMD_SHOW_GPR_LS_OUTPUT}
278285
"Show Ada Language Server for GPR Output")
279286
280-
[$(refresh) Reload Project](command:als-reload-project "Reload Project")
287+
[$(refresh) Reload Project](command:${CMD_RELOAD_PROJECT} "Reload Project")
281288
282-
[$(debug-restart) Restart Language Servers](command:ada.restartLanguageServers
289+
[$(debug-restart) Restart Language Servers](command:${CMD_RESTART_LANG_SERVERS}
283290
"Restart Ada Language Servers")`,
284291
);
285292
};

integration/vscode/ada/src/alsExecuteCommand.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import {
4040
ReplaceTypeCommandArgs,
4141
} from './refactoring/alsReplaceTypeCommand';
4242
import { adaExtState } from './extension';
43+
import { CMD_RELOAD_PROJECT } from './commands';
4344

4445
/**
4546
* Type alias for a function that intercepts a command and executes it by return a promise that
@@ -90,7 +91,7 @@ export const alsCommandExecutor = (client: LanguageClient): CommandExecutor => {
9091
args[0] as ReplaceTypeCommandArgs,
9192
);
9293
if (!proceedWithExecution) return Promise.resolve(undefined);
93-
} else if (command === 'als-reload-project') {
94+
} else if (command === CMD_RELOAD_PROJECT) {
9495
// Clear the cache and the predefined tasks when the project
9596
// has been reloaded.
9697
adaExtState.clearCacheAndTasks('project is being reloaded: clearing caches and tasks');

integration/vscode/ada/src/commands.ts

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,35 @@ export const CMD_SPARK_LIMIT_SUBP_ARG = 'ada.spark.limitSubpArg';
8686
export const CMD_SPARK_LIMIT_REGION_ARG = 'ada.spark.limitRegionArg';
8787
export const CMD_SPARK_PROVE_SUBP = 'ada.spark.proveSubprogram';
8888

89+
/**
90+
* Identifier for the command that shows the extension's output in the Output panel.
91+
*/
92+
export const CMD_SHOW_EXTENSION_LOGS = 'ada.showExtensionOutput';
93+
94+
/**
95+
* Identifier for the command that shows the output of the ALS for Ada in the Output panel.
96+
*/
97+
export const CMD_SHOW_ADA_LS_OUTPUT = 'ada.showAdaLSOutput';
98+
99+
/**
100+
* Identifier for the command that shows the output of the ALS for GPR in the Output panel.
101+
*/
102+
export const CMD_SHOW_GPR_LS_OUTPUT = 'ada.showGprLSOutput';
103+
104+
/**
105+
* Identifier for the command that reloads the currently loaded project on server-side.
106+
*/
107+
export const CMD_RELOAD_PROJECT = 'als-reload-project';
108+
109+
/**
110+
* Identifier for the command that restarts all the language servers spawned by the extension
111+
* (Ada and GPR).
112+
*/
113+
export const CMD_RESTART_LANG_SERVERS = 'ada.restartLanguageServers';
114+
89115
export function registerCommands(context: vscode.ExtensionContext, clients: ExtensionState) {
90116
context.subscriptions.push(
91-
vscode.commands.registerCommand('ada.restartLanguageServers', restartLanguageServers),
117+
vscode.commands.registerCommand(CMD_RESTART_LANG_SERVERS, restartLanguageServers),
92118
);
93119
context.subscriptions.push(
94120
vscode.commands.registerCommand('ada.createHelloWorldProject', createHelloWorldProject),
@@ -116,15 +142,15 @@ export function registerCommands(context: vscode.ExtensionContext, clients: Exte
116142
vscode.commands.registerCommand('ada.subprogramBox', addSubprogramBoxCommand),
117143
);
118144
context.subscriptions.push(
119-
vscode.commands.registerCommand('ada.showExtensionOutput', () => mainOutputChannel.show()),
145+
vscode.commands.registerCommand(CMD_SHOW_EXTENSION_LOGS, () => mainOutputChannel.show()),
120146
);
121147
context.subscriptions.push(
122-
vscode.commands.registerCommand('ada.showAdaLSOutput', () =>
148+
vscode.commands.registerCommand(CMD_SHOW_ADA_LS_OUTPUT, () =>
123149
clients.adaClient.outputChannel.show(),
124150
),
125151
);
126152
context.subscriptions.push(
127-
vscode.commands.registerCommand('ada.showGprLSOutput', () =>
153+
vscode.commands.registerCommand(CMD_SHOW_GPR_LS_OUTPUT, () =>
128154
clients.gprClient.outputChannel.show(),
129155
),
130156
);

integration/vscode/ada/test/general/extension.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { activate, assertEqualToFileContent } from '../utils';
55

66
import { readFileSync, writeFileSync } from 'fs';
77
import * as vscode from 'vscode';
8+
import { CMD_RESTART_LANG_SERVERS } from '../../src/commands';
89

910
suite('Extensions Test Suite', function () {
1011
// Make sure the extension is activated
@@ -139,7 +140,7 @@ suite('Extensions Test Suite', function () {
139140
// Restart the server and check that we still have the same project
140141
// loaded on ALS side
141142
const oldAlsUri = await adaExtState.getProjectUri();
142-
await vscode.commands.executeCommand('ada.restartLanguageServers');
143+
await vscode.commands.executeCommand(CMD_RESTART_LANG_SERVERS);
143144
const newAlsUri = await adaExtState.getProjectUri();
144145
assert.deepStrictEqual(
145146
oldAlsUri?.fsPath,

integration/vscode/ada/test/runTest.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ async function main() {
1010
// Passed to `--extensionDevelopmentPath`
1111
const extensionDevelopmentPath = path.resolve(__dirname, '../../');
1212

13-
const testsuites = ['general', 'gnattest', 'workspace_missing_dirs'];
13+
const testsuites = ['general', 'gnattest', 'workspace_missing_dirs', 'status_bar'];
1414

1515
let someTestsuiteFailed = false;
1616

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
import * as assert from 'assert';
2+
import { activate } from '../utils';
3+
4+
import * as vscode from 'vscode';
5+
import { adaExtState } from '../../src/extension';
6+
import { CMD_RELOAD_PROJECT } from '../../src/commands';
7+
import { readFileSync, writeFileSync } from 'fs';
8+
import { integer } from 'vscode-languageclient';
9+
10+
suite('Status Bar Test Suite', function () {
11+
// Make sure the extension is activated
12+
this.beforeAll(async () => {
13+
await activate();
14+
});
15+
16+
/**
17+
* This function checks diagnostics for the given URI, making sure we have
18+
* the expected count for the given severity.
19+
*/
20+
async function checkDiagnosticsAndStatusBar(
21+
prjUri: vscode.Uri,
22+
nbDiags: integer,
23+
severity: vscode.DiagnosticSeverity,
24+
) {
25+
// Get the diagnostics with the expected severity
26+
const diagnostics = new Promise<vscode.Diagnostic[]>((resolve) => {
27+
const disposable = vscode.languages.onDidChangeDiagnostics(
28+
(e: vscode.DiagnosticChangeEvent) => {
29+
if (e.uris.some((uri) => uri.path == prjUri.path)) {
30+
const diags = vscode.languages.getDiagnostics(prjUri);
31+
if (diags.some((diag) => diag.severity == severity)) {
32+
disposable.dispose();
33+
resolve(diags);
34+
}
35+
}
36+
},
37+
);
38+
});
39+
const alsDiagnostics = await diagnostics;
40+
41+
// Check that we have the diagnostics we expect
42+
assert.strictEqual(
43+
alsDiagnostics.length,
44+
nbDiags,
45+
`Wrong number of project-related diagnostics with ${severity} severity.
46+
Actual diagnostics are:
47+
${JSON.stringify(alsDiagnostics)}`,
48+
);
49+
50+
// Check that the status bar colors have been updated accordingly
51+
const expectedBgColor =
52+
severity == vscode.DiagnosticSeverity.Error
53+
? new vscode.ThemeColor('statusBarItem.errorBackground')
54+
: severity == vscode.DiagnosticSeverity.Warning
55+
? new vscode.ThemeColor('statusBarItem.warningBackground')
56+
: undefined;
57+
const expectedFgColor =
58+
severity == vscode.DiagnosticSeverity.Error
59+
? new vscode.ThemeColor('statusBarItem.errorForeground')
60+
: severity == vscode.DiagnosticSeverity.Warning
61+
? new vscode.ThemeColor('statusBarItem.warningForeground')
62+
: undefined;
63+
64+
assert.deepEqual(
65+
adaExtState.statusBar.backgroundColor,
66+
expectedBgColor,
67+
`Status bar foreground has wrong color for ${severity}`,
68+
);
69+
assert.deepEqual(
70+
adaExtState.statusBar.color,
71+
expectedFgColor,
72+
`Status bar foreground has wrong color for ${severity}`,
73+
);
74+
}
75+
76+
test('Status Bar - Project loaded successfully', () => {
77+
if (vscode.workspace.workspaceFolders !== undefined) {
78+
// Gather all the diagnostics from the interesting ALS diagnostics' sources.
79+
// For the status bar we are interested only in project-related diagnostics.
80+
const alsDiagnostics: vscode.Diagnostic[] = vscode.languages
81+
.getDiagnostics()
82+
.flatMap(([, diagnostics]) => diagnostics)
83+
.filter((diag) => ['ada.project', 'ada.alire'].includes(diag.source ?? ''));
84+
85+
// Check that we don't have any project-related
86+
assert.equal(
87+
alsDiagnostics.length,
88+
0,
89+
'We should not have project-related diagnostics',
90+
);
91+
92+
// Check the status bar colors: they should be transparent
93+
assert.strictEqual(
94+
adaExtState.statusBar.backgroundColor,
95+
undefined,
96+
'Status bar background color should be transparent',
97+
);
98+
assert.strictEqual(
99+
adaExtState.statusBar.color,
100+
undefined,
101+
'Status bar foreground color should be transparent',
102+
);
103+
}
104+
});
105+
106+
test('Status Bar - Project loaded with warnings', async () => {
107+
if (vscode.workspace.workspaceFolders !== undefined) {
108+
// Get the workspace root folder and project URI
109+
const folder = vscode.workspace.workspaceFolders[0].uri;
110+
const prjUri = vscode.Uri.joinPath(folder, 'workspace.gpr');
111+
const contentBefore = readFileSync(prjUri.fsPath, 'utf-8');
112+
113+
try {
114+
// Modify the .gpr file so that we get warnings after reloading it
115+
const newContent = contentBefore.replace(
116+
'for Languages use ("ada");',
117+
'for Languages use ("ada", "c");',
118+
);
119+
writeFileSync(prjUri.fsPath, newContent, 'utf-8');
120+
121+
// Reload the project
122+
await vscode.commands.executeCommand(CMD_RELOAD_PROJECT);
123+
124+
await checkDiagnosticsAndStatusBar(prjUri, 1, vscode.DiagnosticSeverity.Warning);
125+
} finally {
126+
// Restore the old .gpr file content
127+
writeFileSync(prjUri.fsPath, contentBefore);
128+
}
129+
}
130+
});
131+
132+
test('Status Bar - Project loaded with errors', async () => {
133+
if (vscode.workspace.workspaceFolders !== undefined) {
134+
// Get the workspace root folder and project URI
135+
const folder = vscode.workspace.workspaceFolders[0].uri;
136+
const prjUri = vscode.Uri.joinPath(folder, 'workspace.gpr');
137+
const contentBefore = readFileSync(prjUri.fsPath, 'utf-8');
138+
139+
try {
140+
// Modify the .gpr file so that we get warnings after reloading it
141+
const newContent = contentBefore.replace(
142+
'for Languages use ("ada");',
143+
'for Unknown_Attriute use "unknown";',
144+
);
145+
writeFileSync(prjUri.fsPath, newContent, 'utf-8');
146+
147+
// Reload the project
148+
await vscode.commands.executeCommand(CMD_RELOAD_PROJECT);
149+
150+
await checkDiagnosticsAndStatusBar(prjUri, 1, vscode.DiagnosticSeverity.Error);
151+
} finally {
152+
// Restore the old .gpr file content
153+
writeFileSync(prjUri.fsPath, contentBefore);
154+
}
155+
}
156+
});
157+
});
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"ada.projectFile": "workspace.gpr"
3+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
procedure Main is
2+
begin
3+
null;
4+
end Main;

0 commit comments

Comments
 (0)