Skip to content

Commit b025af2

Browse files
Add a 'als-get-project-attribute-value' command
Used to query project attribute values from LSP clients. For eng/ide/ada_language_server#1309
1 parent 8149579 commit b025af2

15 files changed

+647
-70
lines changed

doc/get_project_attribute_value.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Get Project Attribute Value
2+
3+
## Short introduction
4+
5+
This is a custom command used by the VS Code extension to retrieve the value of a project attribute for the
6+
currently loaded project tree.
7+
8+
## Change description
9+
10+
The command's name is the following:
11+
12+
method: `als-get-project-attribute-value`
13+
14+
With the following arguments:
15+
16+
```typescript
17+
18+
type ProjectAttributeValueArgs = {
19+
attribute: string, /* The name of the attribute (e.g: 'Main') */
20+
pkg: string="", /* The name of the package (e.g: 'Compiler'). Can be empty for top-level attributes */
21+
index: string="" /* Index for indexed attributes (e.g: 'Ada' in 'for Default_Switches ("Ada") use ..') */,
22+
}
23+
```
24+
25+
with the associated return type:
26+
27+
```typescript
28+
29+
type ProjectValueResponse = string | string[];
30+
31+
```

integration/vscode/ada/src/ExtensionState.ts

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import * as vscode from 'vscode';
2-
import { Disposable, ExecuteCommandRequest, LanguageClient } from 'vscode-languageclient/node';
2+
import {
3+
Disposable,
4+
ExecuteCommandParams,
5+
ExecuteCommandRequest,
6+
LanguageClient,
7+
} from 'vscode-languageclient/node';
38
import { AdaCodeLensProvider } from './AdaCodeLensProvider';
49
import { createClient } from './clients';
510
import { AdaInitialDebugConfigProvider, initializeDebugging } from './debugConfigProvider';
@@ -183,6 +188,42 @@ export class ExtensionState {
183188
}
184189
};
185190

191+
/**
192+
* Returns the value of the given project attribute, or raises
193+
* an exception when the queried attribute is not known
194+
* (i.e: not registered in GPR2's knowledge database).
195+
*
196+
* @param attribute - The name of the project attribute (e.g: 'Target')
197+
* @param pkg - The name of the attribute's package (e.g: 'Compiler').
198+
* Can be empty for project-level attributes.
199+
* @param index - Attribute's index, if any. Can be a file or a language
200+
* (e.g: 'for Runtime ("Ada") use...').
201+
* @returns the value of the queried project attribute. Can be either a string or a
202+
* list of strings, depending on the attribute itself (e.g: 'Main' attribute is
203+
* specified as a list of strings while 'Target' as a string)
204+
*/
205+
public async getProjectAttributeValue(
206+
attribute: string,
207+
pkg: string = '',
208+
index: string = '',
209+
): Promise<string | string[]> {
210+
const params: ExecuteCommandParams = {
211+
command: 'als-get-project-attribute-value',
212+
arguments: [
213+
{
214+
attribute: attribute,
215+
pkg: pkg,
216+
index: index,
217+
},
218+
],
219+
};
220+
221+
const attrValue = (await this.adaClient.sendRequest(ExecuteCommandRequest.type, params)) as
222+
| string
223+
| string[];
224+
return attrValue;
225+
}
226+
186227
/**
187228
* @returns the URI of the main project file from the ALS
188229
*/

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import assert from 'assert';
22
import { envHasExec, findAdaMain, getSymbols, which } from '../../src/helpers';
33
import { DocumentSymbol, SymbolKind, Uri, commands, workspace } from 'vscode';
44
import { rangeToStr } from '../utils';
5+
import { adaExtState } from '../../src/extension';
56

67
suite('which and envHasExec', function () {
78
test('existing', function () {
@@ -51,6 +52,31 @@ suite('findAdaMain', function () {
5152
});
5253
});
5354

55+
suite('getProjectAttributeValue', function () {
56+
test('Get project attribute value (simple case)', async function () {
57+
/* Basic test for getProjectAttributeValue */
58+
const switches = await adaExtState.getProjectAttributeValue(
59+
'Default_Switches',
60+
'Compiler',
61+
'Ada',
62+
);
63+
assert.deepEqual(switches, ['-g', '-O0']);
64+
});
65+
66+
test('Get unknown project attribute value', async function () {
67+
/* Check that we get an exception when trying to get the value
68+
of an unknown attribute */
69+
70+
let error = undefined;
71+
try {
72+
await adaExtState.getProjectAttributeValue('Unknown');
73+
} catch (e) {
74+
error = e;
75+
}
76+
assert.notEqual(error, undefined);
77+
});
78+
});
79+
5480
suite('getSymbols', function () {
5581
let symbols: DocumentSymbol[];
5682

source/ada/lsp-ada_contexts.adb

Lines changed: 82 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ with GPR2.Containers;
2727
with GPR2.Path_Name;
2828
with GPR2.Project.Attribute;
2929
with GPR2.Project.Attribute_Index;
30+
with GPR2.Project.Registry.Attribute;
3031
with GPR2.Build.Source;
3132
with GPR2.Build.Source.Sets;
3233

@@ -925,73 +926,105 @@ package body LSP.Ada_Contexts is
925926
return Ada.Strings.Unbounded.To_String (Self.Charset);
926927
end Charset;
927928

929+
------------------------------
930+
-- Project_Attribute_Values --
931+
------------------------------
932+
933+
function Project_Attribute_Values
934+
(View : GPR2.Project.View.Object;
935+
Attribute : GPR2.Q_Attribute_Id;
936+
Index : String := "";
937+
Is_List_Attribute : out Boolean;
938+
Is_Known : out Boolean)
939+
return VSS.String_Vectors.Virtual_String_Vector
940+
is
941+
use GPR2.Project.Registry.Attribute;
942+
943+
Attribute_Index : constant GPR2.Project.Attribute_Index.Object :=
944+
(if Index = "" then GPR2.Project.Attribute_Index.Undefined
945+
else GPR2.Project.Attribute_Index.Create (Index));
946+
947+
Attribute_Value : GPR2.Project.Attribute.Object;
948+
949+
function Convert
950+
(Values : GPR2.Containers.Source_Value_List)
951+
return VSS.String_Vectors.Virtual_String_Vector;
952+
953+
-------------
954+
-- Convert --
955+
-------------
956+
957+
function Convert
958+
(Values : GPR2.Containers.Source_Value_List)
959+
return VSS.String_Vectors.Virtual_String_Vector
960+
is
961+
Result : VSS.String_Vectors.Virtual_String_Vector;
962+
begin
963+
for Value of Values loop
964+
Result.Append (VSS.Strings.Conversions.To_Virtual_String (Value.Text));
965+
end loop;
966+
967+
return Result;
968+
end Convert;
969+
970+
begin
971+
Is_Known := False;
972+
973+
if View.Check_Attribute
974+
(Name => Attribute,
975+
Index => Attribute_Index,
976+
Result => Attribute_Value)
977+
then
978+
Is_List_Attribute := (Attribute_Value.Kind = List);
979+
Is_Known := True;
980+
return Convert (Attribute_Value.Values);
981+
end if;
982+
983+
return [];
984+
end Project_Attribute_Values;
985+
928986
-----------------------------
929987
-- Project_Attribute_Value --
930988
-----------------------------
931989

932990
function Project_Attribute_Value
933-
(Self : Context;
991+
(View : GPR2.Project.View.Object;
934992
Attribute : GPR2.Q_Attribute_Id;
935993
Index : String := "";
936-
Default : String := "";
937-
Use_Extended : Boolean := False) return String is
994+
Default : String := "") return String
995+
is
996+
Dummy : Boolean;
997+
Is_Known : Boolean;
998+
Values : constant VSS.String_Vectors.Virtual_String_Vector :=
999+
Project_Attribute_Values
1000+
(View => View,
1001+
Attribute => Attribute,
1002+
Index => Index,
1003+
Is_List_Attribute => Dummy,
1004+
Is_Known => Is_Known);
9381005
begin
939-
return Project_Attribute_Value
940-
(View => Self.Tree.Root_Project,
941-
Attribute => Attribute,
942-
Index => Index,
943-
Default => Default,
944-
Use_Extended => Use_Extended);
1006+
if Is_Known then
1007+
return VSS.Strings.Conversions.To_UTF_8_String (Values.First_Element);
1008+
else
1009+
return Default;
1010+
end if;
9451011
end Project_Attribute_Value;
9461012

9471013
-----------------------------
9481014
-- Project_Attribute_Value --
9491015
-----------------------------
9501016

9511017
function Project_Attribute_Value
952-
(View : GPR2.Project.View.Object;
1018+
(Self : Context;
9531019
Attribute : GPR2.Q_Attribute_Id;
9541020
Index : String := "";
955-
Default : String := "";
956-
Use_Extended : Boolean := False) return String is
957-
Attribute_Index : constant GPR2.Project.Attribute_Index.Object :=
958-
(if Index = ""
959-
then GPR2.Project.Attribute_Index.Undefined
960-
else GPR2.Project.Attribute_Index.Create (Index));
961-
962-
Attribute_Value : GPR2.Project.Attribute.Object;
963-
1021+
Default : String := "") return String is
9641022
begin
965-
if View.Check_Attribute
966-
(Name => Attribute,
967-
Index => Attribute_Index,
968-
Result => Attribute_Value)
969-
then
970-
return Attribute_Value.Value.Text;
971-
elsif Use_Extended and then View.Is_Extending then
972-
-- Look at Extended project list as attribute not found in
973-
-- Root_Project and Use_Extended requested.
974-
975-
declare
976-
Extended_Root : GPR2.Project.View.Object :=
977-
View.Extended_Root;
978-
begin
979-
while Extended_Root.Is_Defined loop
980-
if Extended_Root.Check_Attribute
981-
(Name => Attribute,
982-
Index => Attribute_Index,
983-
Result => Attribute_Value)
984-
then
985-
return Attribute_Value.Value.Text;
986-
elsif Extended_Root.Is_Extending then
987-
Extended_Root := Extended_Root.Extended_Root;
988-
else
989-
Extended_Root := GPR2.Project.View.Undefined;
990-
end if;
991-
end loop;
992-
end;
993-
end if;
994-
return Default;
1023+
return Project_Attribute_Value
1024+
(View => Self.Tree.Root_Project,
1025+
Attribute => Attribute,
1026+
Index => Index,
1027+
Default => Default);
9951028
end Project_Attribute_Value;
9961029

9971030
end LSP.Ada_Contexts;

source/ada/lsp-ada_contexts.ads

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ with Libadalang.Common;
3737
with Utils.Command_Lines;
3838
with Pp.Command_Lines;
3939

40+
with VSS.String_Vectors;
4041
with VSS.Strings;
4142

4243
with LSP.Ada_Documents;
@@ -275,32 +276,57 @@ package LSP.Ada_Contexts is
275276
function Charset (Self : Context) return String;
276277
-- Return the charset for this context
277278

279+
function Project_Attribute_Values
280+
(View : GPR2.Project.View.Object;
281+
Attribute : GPR2.Q_Attribute_Id;
282+
Index : String := "";
283+
Is_List_Attribute : out Boolean;
284+
Is_Known : out Boolean)
285+
return VSS.String_Vectors.Virtual_String_Vector;
286+
-- Returns the values for the given project attribute.
287+
-- The corresponding attribute would have been set in the project as:
288+
-- for Attribute use "value";
289+
-- for Attribute use ("value_1", "value_2");
290+
-- or
291+
-- for Attribute (Index) use "value";
292+
-- for Attribute (Index) use ("value_1", "value_2");
293+
--
294+
-- If the attribute is not defined in the project itself, then the
295+
-- attribute is looked up in the project extended by the project (if
296+
-- any).
297+
-- A default value will always be returned if the attribute is known.
298+
-- Is_List_Attribute will be set to True if the queried attribute is a
299+
-- string list attribute (e.g: for Main use ("main1.adb", "main2.adb"))
300+
-- or set to False if it's a simple string one
301+
-- (e.g: for Target use "arm-eabi");
302+
-- Is_Known will be set to False if the attribute is not known (i.e: not
303+
-- registered in GPR2's knowledge database).
304+
278305
function Project_Attribute_Value
279-
(Self : Context;
306+
(View : GPR2.Project.View.Object;
280307
Attribute : GPR2.Q_Attribute_Id;
281308
Index : String := "";
282-
Default : String := "";
283-
Use_Extended : Boolean := False) return String;
284-
-- Returns the value for Self's project Attribute.
309+
Default : String := "") return String;
310+
-- Returns the value for the given string project Attribute.
285311
-- Default is returned if the attribute wasn't set by the user and
286312
-- has no default value.
287313
-- The corresponding attribute would have been set in the project as:
288314
-- for Attribute use "value";
289315
-- or
290316
-- for Attribute (Index) use "value";
291317
--
292-
-- If Use_Extended is True and the attribute is not defined in Project
293-
-- itself, then the attribute is looked up in the project extended by
294-
-- Project (if any).
318+
-- If the given attribute corresponds to a string list attribute instead
319+
-- (e.g: 'Main' attribute, which takes a list of mains) of a simple string
320+
-- attribute, the first value of the list is returned: if you want to get
321+
-- the full list use the Project_Attribute_Values function instead.
295322

296323
function Project_Attribute_Value
297-
(View : GPR2.Project.View.Object;
324+
(Self : Context;
298325
Attribute : GPR2.Q_Attribute_Id;
299326
Index : String := "";
300-
Default : String := "";
301-
Use_Extended : Boolean := False) return String;
302-
-- Same as above, but computing the value from the given view instead
303-
-- of the context's root project.
327+
Default : String := "") return String;
328+
-- Same as above, but computing the value directly from the context's
329+
-- root project view.
304330

305331
private
306332

source/ada/lsp-ada_driver.adb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ with LSP.Ada_Handlers.Named_Parameters_Commands;
6060
with LSP.Ada_Handlers.Object_Dir_Commands;
6161
with LSP.Ada_Handlers.Other_File_Commands;
6262
with LSP.Ada_Handlers.Open_Project_File_Commands;
63+
with LSP.Ada_Handlers.Project_Attributes_Commands;
6364
with LSP.Ada_Handlers.Project_File_Commands;
6465
with LSP.Ada_Handlers.Project_Reload_Commands;
6566
with LSP.Ada_Handlers.Refactor.Add_Parameter;
@@ -197,6 +198,8 @@ procedure LSP.Ada_Driver is
197198
(LSP.Ada_Handlers.Executables_Commands.Command'Tag);
198199
LSP.Ada_Commands.Register
199200
(LSP.Ada_Handlers.Mains_Commands.Command'Tag);
201+
LSP.Ada_Commands.Register
202+
(LSP.Ada_Handlers.Project_Attributes_Commands.Command'Tag);
200203
LSP.Ada_Commands.Register
201204
(LSP.Ada_Handlers.Project_File_Commands.Command'Tag);
202205
LSP.Ada_Commands.Register

0 commit comments

Comments
 (0)