diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 21ffeb311..de1f91dbc 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -83,6 +83,9 @@ build_and_test: - cp -r $ANOD_DEFAULT_SANDBOX_DIR/log $CI_PROJECT_DIR/anod-logs - echo -e "\e[0Ksection_end:`date +%s`:prepare_artifacts\r\e[0K" + - if [ ! -z ${FAILED+x} ]; then cat $CI_PROJECT_DIR/als_xunit_output.xml; fi + - if [ ! -z ${FAILED+x} ]; then cat $CI_PROJECT_DIR/vscode_xunit_output.xml; fi + - if [ ! -z ${FAILED+x} ]; then echo "There was at least one testcase failure" && exit 1; fi artifacts: diff --git a/source/ada/lsp-ada_handlers.adb b/source/ada/lsp-ada_handlers.adb index 5d4ecb78a..ea49d4dbd 100644 --- a/source/ada/lsp-ada_handlers.adb +++ b/source/ada/lsp-ada_handlers.adb @@ -94,6 +94,7 @@ with LSP.Errors; with LSP.Formatters.Texts; with LSP.Generic_Cancel_Check; with LSP.GNATCOLL_Tracers.Handle; +with LSP.Predefined_Completion; with LSP.Search; with LSP.Server_Notifications.DidChange; with LSP.Servers; @@ -3028,24 +3029,48 @@ package body LSP.Ada_Handlers is Decl_Text : VSS.Strings.Virtual_String; Qualifier_Text : VSS.Strings.Virtual_String; - Comments_Text : VSS.Strings.Virtual_String; + Documentation_Text : VSS.Strings.Virtual_String; Location_Text : VSS.Strings.Virtual_String; Aspects_Text : VSS.Strings.Virtual_String; begin - if Decl.Is_Null or else Self.Is_Canceled.all then + -- Return immediately if the request has been canceled + if Self.Is_Canceled.all then return; end if; - LSP.Ada_Documentation.Get_Tooltip_Text - (BD => Decl, - Style => Context.Get_Documentation_Style, - Declaration_Text => Decl_Text, - Qualifier_Text => Qualifier_Text, - Location_Text => Location_Text, - Documentation_Text => Comments_Text, - Aspects_Text => Aspects_Text); + if Decl.Is_Null then + + -- There is no declaration for the hovered node: ask the predefined + -- entities' completion provider (attributes, pragmas, aspects) for + -- a tooltip text if it can. + declare + Node : constant Libadalang.Analysis.Ada_Node := Self.Get_Node_At + (Context.all, Value); + begin + if not Node.Is_Null + and then Node.Kind in Libadalang.Common.Ada_Identifier_Range + then + LSP.Predefined_Completion.Get_Tooltip_Text + (Node => Node.As_Identifier, + Declaration_Text => Decl_Text, + Documentation_Text => Documentation_Text); + end if; + end; + else + -- We have resolved the hovered node to its declaration: use + -- the default tooltip provider, based on GNATdoc. + LSP.Ada_Documentation.Get_Tooltip_Text + (BD => Decl, + Style => Context.Get_Documentation_Style, + Declaration_Text => Decl_Text, + Qualifier_Text => Qualifier_Text, + Location_Text => Location_Text, + Documentation_Text => Documentation_Text, + Aspects_Text => Aspects_Text); + end if; + -- Return if no provider has been able to compute text for a tooltip. if Decl_Text.Is_Empty then return; end if; @@ -3075,28 +3100,30 @@ package body LSP.Ada_Handlers is -- In addition, append the project's name if we are dealing with an -- aggregate project. - Location_Text := LSP.Utils.Node_Location_Image (Decl); + if not Decl.Is_Null then + Location_Text := LSP.Utils.Node_Location_Image (Decl); - if Self.Project_Tree.Root_Project.Kind in GPR2.Aggregate_Kind then - Location_Text.Append (VSS.Characters.Latin.Line_Feed); - Location_Text.Append ("As defined in project "); - Location_Text.Append (Context.Id); - Location_Text.Append (" (other projects skipped)."); - end if; + if Self.Project_Tree.Root_Project.Kind in GPR2.Aggregate_Kind then + Location_Text.Append (VSS.Characters.Latin.Line_Feed); + Location_Text.Append ("As defined in project "); + Location_Text.Append (Context.Id); + Location_Text.Append (" (other projects skipped)."); + end if; - Response.Value.contents.MarkedString_Vector.Append - (LSP.Structures.MarkedString' - (Is_Virtual_String => True, - Virtual_String => Location_Text)); + Response.Value.contents.MarkedString_Vector.Append + (LSP.Structures.MarkedString' + (Is_Virtual_String => True, + Virtual_String => Location_Text)); + end if; -- Append the comments associated with the basic declaration if any. - if not Comments_Text.Is_Empty then + if not Documentation_Text.Is_Empty then Response.Value.contents.MarkedString_Vector.Append (LSP.Structures.MarkedString' (Is_Virtual_String => False, language => "plaintext", - value => Comments_Text)); + value => Documentation_Text)); end if; -- Append text of aspects diff --git a/source/ada/lsp-predefined_completion.adb b/source/ada/lsp-predefined_completion.adb index c674ac05b..9aa7e194a 100644 --- a/source/ada/lsp-predefined_completion.adb +++ b/source/ada/lsp-predefined_completion.adb @@ -28,6 +28,7 @@ with VSS.Strings.Conversions; with LSP.Enumerations; with LSP.Predefined_Completion.Ada2012; +with Libadalang.Common; package body LSP.Predefined_Completion is @@ -277,4 +278,52 @@ package body LSP.Predefined_Completion is end; end Get_Output; + ---------------------- + -- Get_Tooltip_Text -- + ---------------------- + + procedure Get_Tooltip_Text + (Node : Libadalang.Analysis.Identifier; + Declaration_Text : out VSS.Strings.Virtual_String; + Documentation_Text : out VSS.Strings.Virtual_String) + is + use Libadalang.Common; + + Filtered_Items : CompletionItem_Vector; + Prefix : VSS.Strings.Virtual_String; + Parent : constant Libadalang.Analysis.Ada_Node := + (if Node.Is_Null then Libadalang.Analysis.No_Ada_Node + else Node.Parent); + Item : CompletionItem; + begin + -- Return immediately if the node is null of if its parent is null + if Node.Is_Null or else Parent.Is_Null then + return; + end if; + + -- Get the attribute/aspect/pragma completion item corresponding to the + -- given node + + Prefix := VSS.Strings.To_Virtual_String (Node.Text); + + case Parent.Kind is + when Ada_Attribute_Ref_Range => + Get_Attributes (Prefix => Prefix, Result => Filtered_Items); + + when Ada_Aspect_Assoc_Range => + Get_Aspects (Prefix => Prefix, Result => Filtered_Items); + + when Ada_Pragma_Node_Range => + Get_Pragmas (Prefix => Prefix, Result => Filtered_Items); + + when others => + return; + end case; + + Item := Filtered_Items.First_Element; + + Declaration_Text := Item.detail; + Documentation_Text := Item.documentation.Value.Virtual_String; + end Get_Tooltip_Text; + end LSP.Predefined_Completion; diff --git a/source/ada/lsp-predefined_completion.ads b/source/ada/lsp-predefined_completion.ads index 65c5960f4..732fc049d 100644 --- a/source/ada/lsp-predefined_completion.ads +++ b/source/ada/lsp-predefined_completion.ads @@ -20,6 +20,7 @@ with GNATCOLL.Traces; use GNATCOLL.Traces; with VSS.Strings; with LSP.Structures; use LSP.Structures; +with Libadalang.Analysis; package LSP.Predefined_Completion is @@ -43,4 +44,19 @@ package LSP.Predefined_Completion is Result : in out CompletionItem_Vector); -- Return completion for pragmas, filtering the results using Prefix. + procedure Get_Tooltip_Text + (Node : Libadalang.Analysis.Identifier; + Declaration_Text : out VSS.Strings.Virtual_String; + Documentation_Text : out VSS.Strings.Virtual_String); + -- Get all the information needed to produce tooltips (hover and completion + -- requests) for the given node, if it's a predefined entity (e.g: aspect, + -- pragma or attribute). + -- + -- @param Node + -- The predefined entity's node. + -- @param Declaration_Text + -- Contains the code corresponding to the predefined entity's declaration. + -- @param Documentation_Text + -- Contains the documentation associated to the predefined entity. + end LSP.Predefined_Completion; diff --git a/source/gpr/lsp-gpr_client_capabilities.adb b/source/gpr/lsp-gpr_client_capabilities.adb new file mode 100644 index 000000000..fe05349af --- /dev/null +++ b/source/gpr/lsp-gpr_client_capabilities.adb @@ -0,0 +1,55 @@ +------------------------------------------------------------------------------ +-- Language Server Protocol -- +-- -- +-- Copyright (C) 2023, AdaCore -- +-- -- +-- This is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 3, or (at your option) any later ver- -- +-- sion. This software is distributed in the hope that it will be useful, -- +-- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- +-- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -- +-- License for more details. You should have received a copy of the GNU -- +-- General Public License distributed with this software; see file -- +-- COPYING3. If not, go to http://www.gnu.org/licenses for a complete copy -- +-- of the license. -- +------------------------------------------------------------------------------ + +pragma Ada_2022; + +with VSS.String_Vectors; + +with LSP.Structures.Unwrap; + +package body LSP.GPR_Client_Capabilities is + + ---------------- + -- Initialize -- + ---------------- + + procedure Initialize + (Self : in out Client_Capability'Class; + Value : LSP.Structures.InitializeParams) is + begin + Self.Value := Value; + end Initialize; + + -------------------- + -- Resolve_Lazily -- + -------------------- + + function Resolve_Lazily (Self : Client_Capability'Class) return Boolean is + use LSP.Structures.Unwrap; + + List : constant VSS.String_Vectors.Virtual_String_Vector := + properties + (resolveSupport + (completionItem + (completion + (Self.Value.capabilities.textDocument)))); + + begin + return List.Contains ("detail") and then List.Contains ("documentation"); + end Resolve_Lazily; + +end LSP.GPR_Client_Capabilities; diff --git a/source/gpr/lsp-gpr_client_capabilities.ads b/source/gpr/lsp-gpr_client_capabilities.ads new file mode 100644 index 000000000..df28e6dfa --- /dev/null +++ b/source/gpr/lsp-gpr_client_capabilities.ads @@ -0,0 +1,40 @@ +------------------------------------------------------------------------------ +-- Language Server Protocol -- +-- -- +-- Copyright (C) 2023, AdaCore -- +-- -- +-- This is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 3, or (at your option) any later ver- -- +-- sion. This software is distributed in the hope that it will be useful, -- +-- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- +-- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -- +-- License for more details. You should have received a copy of the GNU -- +-- General Public License distributed with this software; see file -- +-- COPYING3. If not, go to http://www.gnu.org/licenses for a complete copy -- +-- of the license. -- +------------------------------------------------------------------------------ + +with LSP.Structures; + +package LSP.GPR_Client_Capabilities is + + type Client_Capability is tagged limited private; + -- This type holds client initialization response and provides handy + -- queries on the client capabilities + + procedure Initialize + (Self : in out Client_Capability'Class; + Value : LSP.Structures.InitializeParams); + -- Save initialize parameters + + function Resolve_Lazily (Self : Client_Capability'Class) return Boolean; + -- Returns True when resolve contains `documentation` and `details` + +private + + type Client_Capability is tagged limited record + Value : LSP.Structures.InitializeParams; + end record; + +end LSP.GPR_Client_Capabilities; diff --git a/source/gpr/lsp-gpr_completions.adb b/source/gpr/lsp-gpr_completions.adb new file mode 100644 index 000000000..439abbe53 --- /dev/null +++ b/source/gpr/lsp-gpr_completions.adb @@ -0,0 +1,306 @@ +------------------------------------------------------------------------------ +-- Language Server Protocol -- +-- -- +-- Copyright (C) 2023, AdaCore -- +-- -- +-- This is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 3, or (at your option) any later ver- -- +-- sion. This software is distributed in the hope that it will be useful, -- +-- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- +-- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -- +-- License for more details. You should have received a copy of the GNU -- +-- General Public License distributed with this software; see file -- +-- COPYING3. If not, go to http://www.gnu.org/licenses for a complete copy -- +-- of the license. -- +------------------------------------------------------------------------------ + +with Ada.Characters.Conversions; +with Ada.Characters.Handling; + +with GPR2.Project.Registry.Attribute; +with GPR2.Project.Registry.Attribute.Description; +with GPR2.Project.Registry.Pack; +with GPR2.Project.Registry.Pack.Description; + +with Gpr_Parser.Common; +with Gpr_Parser_Support.Text; + +with LSP.Structures.LSPAny_Vectors; + +with VSS.String_Vectors; +with VSS.Strings.Conversions; + +package body LSP.GPR_Completions is + + use GPR2; + + package GPC renames Gpr_Parser.Common; + package PRA renames GPR2.Project.Registry.Attribute; + package PRAD renames GPR2.Project.Registry.Attribute.Description; + package PRP renames GPR2.Project.Registry.Pack; + package PRPD renames GPR2.Project.Registry.Pack.Description; + + procedure Fill_Attribute_Completion_Response + (File : LSP.GPR_Files.File; + Position : LSP.Structures.Position; + Doc : Boolean; + Filter : String; + Response : in out LSP.Structures.Completion_Result); + -- Handle completion when cursor after for keyword + + procedure Fill_Package_Completion_Response + (File : LSP.GPR_Files.File; + Doc : Boolean; + Filter : String; + Response : in out LSP.Structures.Completion_Result); + -- Handle completion when cursor after package keyword + + ---------------------------------------- + -- Fill_Attribute_Completion_Response -- + ---------------------------------------- + + procedure Fill_Attribute_Completion_Response + (File : LSP.GPR_Files.File; + Position : LSP.Structures.Position; + Doc : Boolean; + Filter : String; + Response : in out LSP.Structures.Completion_Result) is + Starts : constant String := Ada.Characters.Handling.To_Lower (Filter); + Current_Package : constant Package_Id := + File.Get_Package (Position); + begin + if Current_Package = Project_Level_Scope + or else PRP.Is_Allowed_In (Current_Package, File.Kind) + then + for Id of PRA.All_Attributes (Current_Package) loop + declare + Item : LSP.Structures.CompletionItem; + Attr : constant String := + Ada.Characters.Handling.To_Lower + (String (Name (Id.Attr))); + begin + if PRA.Get (Id).Is_Allowed_In (File.Kind) + and then + (Starts'Length = 0 + or else (Starts'Length <= Attr'Length + and then Filter = Attr + (Attr'First .. Attr'First + Starts'Length - 1))) + then + Item.label := VSS.Strings.Conversions.To_Virtual_String + (Image (Id.Attr)); + + declare + V : VSS.String_Vectors.Virtual_String_Vector; + begin + V.Append (VSS.Strings.Conversions. + To_Virtual_String (Image (Current_Package))); + V.Append (VSS.Strings.Conversions. + To_Virtual_String (Image (Id.Attr))); + LSP.Structures.LSPAny_Vectors.To_Any + (V, Item.data); + end; + + if Doc then + Item.documentation := + (Is_Set => True, + Value => (Is_Virtual_String => True, + Virtual_String => + VSS.Strings.Conversions.To_Virtual_String + (PRAD.Get_Attribute_Description + (Id)))); + end if; + + Response.Variant_2.items.Append (Item); + end if; + end; + end loop; + end if; + end Fill_Attribute_Completion_Response; + + -------------------------------------- + -- Fill_Package_Completion_Response -- + -------------------------------------- + + procedure Fill_Package_Completion_Response + (File : LSP.GPR_Files.File; + Doc : Boolean; + Filter : String; + Response : in out LSP.Structures.Completion_Result) is + Starts : constant String := Ada.Characters.Handling.To_Lower (Filter); + Kind : constant Project_Kind := File.Kind; + begin + for Id of PRP.All_Packages loop + declare + Item : LSP.Structures.CompletionItem; + Pack : constant String := + Ada.Characters.Handling.To_Lower (String (Name (Id))); + begin + if not File.In_Packages (Id) + and then PRP.Is_Allowed_In (Id, Kind) + and then + (Starts'Length = 0 + or else (Starts'Length <= Pack'Length + and then Filter = Pack + (Pack'First .. Pack'First + Starts'Length - 1))) + then + Item.label := VSS.Strings.Conversions.To_Virtual_String + (Image (Id)); + + declare + V : VSS.String_Vectors.Virtual_String_Vector; + begin + V.Append (VSS.Strings.Conversions.To_Virtual_String + (Image (Id))); + LSP.Structures.LSPAny_Vectors.To_Any + (V, Item.data); + end; + + if Doc then + Item.documentation := + (Is_Set => True, + Value => (Is_Virtual_String => True, + Virtual_String => + VSS.Strings.Conversions.To_Virtual_String + (PRP.Description.Get_Package_Description + (Id)))); + end if; + + Response.Variant_2.items.Append (Item); + end if; + end; + end loop; + end Fill_Package_Completion_Response; + + ------------------------------ + -- Fill_Completion_Response -- + ------------------------------ + + procedure Fill_Completion_Response + (File_Provider : LSP.GPR_Files.File_Provider_Access; + Value : LSP.Structures.CompletionParams; + Compute_Doc_And_Details : Boolean; + Response : in out LSP.Structures.Completion_Result) + is + File : constant LSP.GPR_Files.File_Access := + LSP.GPR_Files.Parse + (File_Provider => File_Provider, + Path => File_Provider.To_File + (Value.textDocument.uri)); + Current : constant GPC.Token_Reference := File.Token (Value.position); + In_Comment : constant Boolean := + LSP.GPR_Files.Position_Is_In_Comment + (Current, Value.position); + Previous : constant GPC.Token_Reference := Current.Previous (True); + + function To_String + (Text : Gpr_Parser_Support.Text.Text_Type) return String is + (Ada.Characters.Handling.To_Lower + (Ada.Characters.Conversions.To_String (Text))); + + use type GPC.Token_Reference, GPC.Token_Kind; + + begin + if not In_Comment then + if Current.Data.Kind in + GPC.Gpr_Whitespace | GPC.Gpr_Comment | GPC.Gpr_Termination + and then Previous /= GPC.No_Token + then + if Previous.Data.Kind in GPC.Gpr_For | GPC.Gpr_Package then + if not LSP.GPR_Files.At_End (Previous, Value.position) then + case Previous.Data.Kind is + + when GPC.Gpr_For => + Fill_Attribute_Completion_Response + (File => File.all, + Position => Value.position, + Doc => Compute_Doc_And_Details, + Filter => "", + Response => Response); + + when GPC.Gpr_Package => + Fill_Package_Completion_Response + (File => File.all, + Doc => Compute_Doc_And_Details, + Filter => "", + Response => Response); + + when others => + null; + + end case; + end if; + + elsif Previous.Data.Kind = GPC.Gpr_Identifier + and then LSP.GPR_Files.At_End (Previous, Value.position) + then + declare + Before_Identifier : constant GPC.Token_Reference := + Previous.Previous (True); + begin + if Before_Identifier /= GPC.No_Token then + case Before_Identifier.Data.Kind is + + when GPC.Gpr_For => + Fill_Attribute_Completion_Response + (File => File.all, + Position => Value.position, + Doc => Compute_Doc_And_Details, + Filter => To_String (Previous.Text), + Response => Response); + + when GPC.Gpr_Package => + Fill_Package_Completion_Response + (File => File.all, + Doc => Compute_Doc_And_Details, + Filter => To_String (Previous.Text), + Response => Response); + + when others => + null; + + end case; + end if; + end; + end if; + end if; + end if; + end Fill_Completion_Response; + + procedure Fill_Completion_Resolve_Response + (Response : in out LSP.Structures.CompletionItem) is + Pack : Package_Id; + Attr : Q_Optional_Attribute_Id; + Doc_Text : VSS.Strings.Virtual_String; + + C : LSP.Structures.JSON_Event_Vectors.Cursor := + Response.data.First; + + V : constant VSS.String_Vectors.Virtual_String_Vector := + LSP.Structures.LSPAny_Vectors.From_Any + (LSP.Structures.JSON_Event_Vectors.Cursor (C)); + begin + Pack := +Optional_Name_Type (VSS.Strings.Conversions.To_UTF_8_String + (V.First_Element)); + if V.Length > 1 then + Attr := (Pack, + +Optional_Name_Type (VSS.Strings.Conversions.To_UTF_8_String + (V.Last_Element))); + + Doc_Text := VSS.Strings.Conversions.To_Virtual_String + (PRAD.Get_Attribute_Description (Attr)); + + else + Doc_Text := VSS.Strings.Conversions.To_Virtual_String + (PRPD.Get_Package_Description (Pack)); + end if; + + Response.documentation := + (Is_Set => True, + Value => LSP.Structures.Virtual_String_Or_MarkupContent' + (Is_Virtual_String => True, + Virtual_String => Doc_Text)); + + end Fill_Completion_Resolve_Response; + +end LSP.GPR_Completions; diff --git a/source/gpr/lsp-gpr_completions.ads b/source/gpr/lsp-gpr_completions.ads new file mode 100644 index 000000000..07f208348 --- /dev/null +++ b/source/gpr/lsp-gpr_completions.ads @@ -0,0 +1,35 @@ +------------------------------------------------------------------------------ +-- Language Server Protocol -- +-- -- +-- Copyright (C) 2023, AdaCore -- +-- -- +-- This is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 3, or (at your option) any later ver- -- +-- sion. This software is distributed in the hope that it will be useful, -- +-- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- +-- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -- +-- License for more details. You should have received a copy of the GNU -- +-- General Public License distributed with this software; see file -- +-- COPYING3. If not, go to http://www.gnu.org/licenses for a complete copy -- +-- of the license. -- +------------------------------------------------------------------------------ + +-- This package provides completion related requests handler for GPR language. + +with LSP.GPR_Files; + +with LSP.Structures; + +package LSP.GPR_Completions is + + procedure Fill_Completion_Response + (File_Provider : LSP.GPR_Files.File_Provider_Access; + Value : LSP.Structures.CompletionParams; + Compute_Doc_And_Details : Boolean; + Response : in out LSP.Structures.Completion_Result); + + procedure Fill_Completion_Resolve_Response + (Response : in out LSP.Structures.CompletionItem); + +end LSP.GPR_Completions; diff --git a/source/gpr/lsp-gpr_documentation.adb b/source/gpr/lsp-gpr_documentation.adb index a1c5a862b..26d807938 100644 --- a/source/gpr/lsp-gpr_documentation.adb +++ b/source/gpr/lsp-gpr_documentation.adb @@ -41,23 +41,31 @@ package body LSP.GPR_Documentation is Tooltip_Text.Clear; - if Token.Data.Kind = Gpr_Identifier then - case Token.Previous (Exclude_Trivia => True).Data.Kind is - when Gpr_Package | Gpr_End => - Tooltip_Text.Append - (VSS.Strings.Conversions.To_Virtual_String - (Get_Package_Description (Self.Get_Package (Position)))); + if Token /= No_Token and then Token.Data.Kind = Gpr_Identifier then + declare + Previous : constant Token_Reference := + Token.Previous (Exclude_Trivia => True); + begin + if Previous /= No_Token then + case Previous.Data.Kind is + when Gpr_Package | Gpr_End => + Tooltip_Text.Append + (VSS.Strings.Conversions.To_Virtual_String + (Get_Package_Description + (Self.Get_Package (Position)))); - when Gpr_For => - Tooltip_Text.Append - (VSS.Strings.Conversions.To_Virtual_String - (Get_Attribute_Description (( - Self.Get_Package (Position), - +(Optional_Name_Type (To_String (Token.Text))))))); + when Gpr_For => + Tooltip_Text.Append + (VSS.Strings.Conversions.To_Virtual_String + (Get_Attribute_Description (( + Self.Get_Package (Position), + +(Optional_Name_Type (To_String (Token.Text))))))); - when others => - null; - end case; + when others => + null; + end case; + end if; + end; end if; end Get_Tooltip_Text; diff --git a/source/gpr/lsp-gpr_files.adb b/source/gpr/lsp-gpr_files.adb index 74d3e7a4c..8c1ed8a07 100644 --- a/source/gpr/lsp-gpr_files.adb +++ b/source/gpr/lsp-gpr_files.adb @@ -884,6 +884,7 @@ package body LSP.GPR_Files is end; Index := Next_Token (Index); end loop; + File.Import_Partition_End := Index.Data.Index; end Parse_Imported_Partition; ------------------------------- @@ -897,10 +898,26 @@ package body LSP.GPR_Files is Extended_Index : GPC.Token_Reference; Name : Unbounded_String; Project_Token : GPR_Token; + begin + File.Project_Definition_Start := No_Token_Index; while Index < Last loop declare Token : constant GPR_Token := Get_GPR_Token (Index); + + procedure Set_Project_Definition_Start; + + ---------------------------------- + -- Set_Project_Definition_Start -- + ---------------------------------- + + procedure Set_Project_Definition_Start is + begin + if File.Project_Definition_Start = No_Token_Index then + File.Project_Definition_Start := Token.Index; + end if; + end Set_Project_Definition_Start; + begin case Token.Kind is when Gpr_Parser.Common.Gpr_Identifier => @@ -909,25 +926,30 @@ package body LSP.GPR_Files is To_Lower_String (Token.Ref); begin if Identifier = "project" then + Set_Project_Definition_Start; Project_Token := Token; elsif Identifier = "library" then + Set_Project_Definition_Start; if File.Kind = GPR2.K_Aggregate then File.Kind := GPR2.K_Aggregate_Library; else File.Kind := GPR2.K_Library; end if; elsif Identifier = "aggregate" then + Set_Project_Definition_Start; File.Kind := GPR2.K_Aggregate; elsif Identifier = "configuration" then + Set_Project_Definition_Start; File.Kind := GPR2.K_Configuration; elsif Identifier = "standard" then - null; + Set_Project_Definition_Start; else Ada.Strings.Unbounded.Append (Name, To_String (Token.Ref)); end if; end; when Gpr_Parser.Common.Gpr_Abstract => + Set_Project_Definition_Start; File.Kind := GPR2.K_Abstract; when Gpr_Parser.Common.Gpr_Dot => Ada.Strings.Unbounded.Append (Name, "."); @@ -1106,4 +1128,80 @@ package body LSP.GPR_Files is end Token; + ---------------------------- + -- Position_Is_In_Comment -- + ---------------------------- + + function Position_Is_In_Comment + (Token : Gpr_Parser.Common.Token_Reference; + Position : LSP.Structures.Position) return Boolean is + Token_Kind : constant Gpr_Parser.Common.Token_Kind := + Gpr_Parser.Common.Kind (Token.Data); + begin + if Token_Kind = GPC.Gpr_Comment then + return not At_Start (Token, Position); + elsif Token_Kind in GPC.Gpr_Whitespace | GPC.Gpr_Termination then + declare + Previous : constant GPC.Token_Reference := Token.Previous; + begin + if Previous /= GPC.No_Token and then + Previous.Data.Kind = GPC.Gpr_Comment and then + Previous.Data.Sloc_Range.End_Line = To_Line_Number (Position.line) + then + return True; + end if; + end; + end if; + return False; + end Position_Is_In_Comment; + + ------------------------------- + -- Token_In_Import_Partition -- + ------------------------------- + + function Token_In_Import_Partition + (Self : File; + Token : Gpr_Parser.Common.Token_Reference) return Boolean is + begin + return Token.Data.Index < Self.Import_Partition_End; + end Token_In_Import_Partition; + + ----------------------------------- + -- Token_At_Import_Partition_End -- + ----------------------------------- + + function Token_At_Import_Partition_End + (Self : File; + Token : Gpr_Parser.Common.Token_Reference) return Boolean is + begin + return Self.Token_In_Import_Partition (Token) and then + Next (Token).Data.Index = Self.Import_Partition_End; + end Token_At_Import_Partition_End; + + -------------------------------- + -- Position_At_Identifier_End -- + -------------------------------- + + function Position_At_Identifier_End + (Token : Gpr_Parser.Common.Token_Reference; + Position : LSP.Structures.Position) return Boolean is + Data : constant GPC.Token_Data_Type := Token.Data; + Kind : constant GPC.Token_Kind := Data.Kind; + Sloc_Range : constant Source_Location_Range := Data.Sloc_Range; + begin + if Kind in GPC.Gpr_Whitespace | GPC.Gpr_Comment | GPC.Gpr_Termination + then + declare + Previous : constant GPC.Token_Reference := Token.Previous; + begin + return Previous /= GPC.No_Token + and then Previous.Data.Kind = GPC.Gpr_Identifier + and then At_Start (Sloc_Range, Position); + end; + elsif Kind = GPC.Gpr_Identifier then + return At_End (Sloc_Range, Position); + end if; + return False; + end Position_At_Identifier_End; + end LSP.GPR_Files; diff --git a/source/gpr/lsp-gpr_files.ads b/source/gpr/lsp-gpr_files.ads index bdf111734..7d82dd8ff 100644 --- a/source/gpr/lsp-gpr_files.ads +++ b/source/gpr/lsp-gpr_files.ads @@ -82,9 +82,26 @@ package LSP.GPR_Files is function Get_File_Reader (Self : access File_Provider) return GPR2.File_Readers.File_Reader_Reference is abstract; - -- Reader used to access opened document buffer or disk. + function To_File + (Self : access File_Provider; + Item : LSP.Structures.DocumentUri) + return GNATCOLL.VFS.Virtual_File is abstract; + -- Turn URI into Virtual_File + + function To_File + (Self : access File_Provider; + Item : LSP.Structures.DocumentUri) + return GPR2.Path_Name.Object is abstract; + -- Turn URI into GPR2 path object. + + function To_URI + (Self : access File_Provider; + Item : GPR2.Path_Name.Object) + return LSP.Structures.DocumentUri is abstract; + -- Turn GPR2 path object into URI. + procedure Initialize (Self : in out File; Path : GPR2.Path_Name.Object; @@ -110,12 +127,39 @@ package LSP.GPR_Files is -- return the Position's Package_Id. Returns Project_Level_Scope if -- Position not inside a package. + function Kind (Self : File) return GPR2.Project_Kind; + -- return project kind as defined in project qualifier + function Token (Self : File; Position : LSP.Structures.Position) return Gpr_Parser.Common.Token_Reference; -- Return File's Token at Position. + function In_Packages + (Self : File; + Name : GPR2.Package_Id) return Boolean; + -- Return True is Name is part of File's packages. + + function Position_Is_In_Comment + (Token : Gpr_Parser.Common.Token_Reference; + Position : LSP.Structures.Position) return Boolean; + -- Return True if Token's Position is inside a comment + + function Position_At_Identifier_End + (Token : Gpr_Parser.Common.Token_Reference; + Position : LSP.Structures.Position) return Boolean; + -- Return True if Token is an identifier & Position is at end of Token or + -- Token is white space + + function Token_In_Import_Partition + (Self : File; + Token : Gpr_Parser.Common.Token_Reference) return Boolean; + + function Token_At_Import_Partition_End + (Self : File; + Token : Gpr_Parser.Common.Token_Reference) return Boolean; + ------------------------------------------------- -- GPR Parser / LSP Slocs-Position conversions -- ------------------------------------------------- @@ -143,6 +187,32 @@ package LSP.GPR_Files is return LSP.Structures.Position is (To_Position_Value (Location.Line), To_Position_Value (Location.Column)); + function At_Start + (Sloc_Range : Gpr_Parser_Support.Slocs.Source_Location_Range; + Position : LSP.Structures.Position) return Boolean is + (Sloc_Range.Start_Line = To_Line_Number (Position.line) and then + Sloc_Range.Start_Column = To_Column_Number (Position.character)); + -- Return True if Position at Sloc_Range's beginning + + function At_Start + (Token : Gpr_Parser.Common.Token_Reference; + Position : LSP.Structures.Position) return Boolean is + (At_Start (Token.Data.Sloc_Range, Position)); + -- Return True if Position at Token's beginning + + function At_End + (Sloc_Range : Gpr_Parser_Support.Slocs.Source_Location_Range; + Position : LSP.Structures.Position) return Boolean is + (Sloc_Range.End_Line = To_Line_Number (Position.line) and then + Sloc_Range.End_Column = To_Column_Number (Position.character)); + -- Return True if Position at Sloc_Range's end + + function At_End + (Token : Gpr_Parser.Common.Token_Reference; + Position : LSP.Structures.Position) return Boolean is + (At_End (Token.Data.Sloc_Range, Position)); + -- Return True if Position at Token's end + private use GPR2; @@ -410,6 +480,12 @@ private File_Provider : File_Provider_Access; -- provider used to get referenced gpr files + Import_Partition_End : TDH.Token_Index := TDH.No_Token_Index; + -- First token not in import partition. + + Project_Definition_Start : TDH.Token_Index := TDH.No_Token_Index; + -- project definition first token (project, abstract, library, ... ) + Name : Project_Id := No_Project; -- project_id of this gpr file @@ -503,4 +579,11 @@ private function Image (Id : Project_Id) return VSS.Strings.Virtual_String is (Image (Project_List, Natural (Id))); + function In_Packages + (Self : File; + Name : Package_Id) return Boolean is + (Self.Packages.Contains (Name)); + + function Kind (Self : File) return GPR2.Project_Kind is (Self.Kind); + end LSP.GPR_Files; diff --git a/source/gpr/lsp-gpr_handlers.adb b/source/gpr/lsp-gpr_handlers.adb index 0714f933c..f0cd991b5 100644 --- a/source/gpr/lsp-gpr_handlers.adb +++ b/source/gpr/lsp-gpr_handlers.adb @@ -25,6 +25,7 @@ with GPR2.Message; with GPR2.Path_Name.Set; with GPR2.Source_Reference; +with LSP.GPR_Completions; with LSP.Constants; with LSP.Enumerations; with LSP.Generic_Cancel_Check; @@ -33,9 +34,6 @@ with LSP.GPR_File_Readers; with LSP.GPR_Files.Symbols; with LSP.Servers; with LSP.Server_Notifications.DidChange; -with URIs; - -with VSS.Strings.Conversions; package body LSP.GPR_Handlers is @@ -44,21 +42,6 @@ package body LSP.GPR_Handlers is GNATCOLL.Traces.On); -- Trace to activate the support for incremental text changes. - function To_File - (Self : Message_Handler'Class; - Item : LSP.Structures.DocumentUri) return GNATCOLL.VFS.Virtual_File; - -- Turn URI into Virtual_File - - function To_File - (Self : Message_Handler'Class; - Item : LSP.Structures.DocumentUri) return GPR2.Path_Name.Object; - -- Turn URI into GPR2 path object. - - function To_URI - (Self : Message_Handler'Class; - Item : GPR2.Path_Name.Object) return LSP.Structures.DocumentUri; - -- Turn GPR2 path object into URI. - procedure Publish_Diagnostics (Self : access Message_Handler'Class; Document : not null LSP.GPR_Documents.Document_Access); @@ -488,13 +471,20 @@ package body LSP.GPR_Handlers is Id : LSP.Structures.Integer_Or_Virtual_String; Value : LSP.Structures.InitializeParams) is - Response : LSP.Structures.InitializeResult; + Response : LSP.Structures.InitializeResult; Capabilities : LSP.Structures.ServerCapabilities; begin Self.File_Reader := LSP.GPR_File_Readers.Create (Self'Unchecked_Access); + Self.Client.Initialize (Value); + Capabilities.hoverProvider := LSP.Constants.True; + Capabilities.completionProvider := + (Is_Set => True, + Value => (triggerCharacters => [" "], + resolveProvider => LSP.Constants.True, + others => <>)); Response.capabilities := Capabilities; @@ -525,6 +515,61 @@ package body LSP.GPR_Handlers is Self.Sender.On_Initialize_Response (Id, Response); end On_Initialize_Request; + --------------------------- + -- On_Completion_Request -- + --------------------------- + + overriding procedure On_Completion_Request + (Self : in out Message_Handler; + Id : LSP.Structures.Integer_Or_Virtual_String; + Value : LSP.Structures.CompletionParams) + is + -- If lazy computation for the 'detail' and 'documentation' fields is + -- supported by the client, set the Compute_Doc_And_Details flag to + -- False. + Compute_Doc_And_Details : constant Boolean := + not Self.Client.Resolve_Lazily; + + Response : LSP.Structures.Completion_Result + (Kind => LSP.Structures.Variant_2); + begin + Response.Variant_2.isIncomplete := False; + + LSP.GPR_Completions.Fill_Completion_Response + (File_Provider => Self'Unchecked_Access, + Value => Value, + Compute_Doc_And_Details => Compute_Doc_And_Details, + Response => Response); + + Self.Sender.On_Completion_Response (Id, Response); + end On_Completion_Request; + + ----------------------------------- + -- On_Completion_Resolve_Request -- + ----------------------------------- + + overriding procedure On_Completion_Resolve_Request + (Self : in out Message_Handler; + Id : LSP.Structures.Integer_Or_Virtual_String; + Value : LSP.Structures.CompletionItem) + is + Response : LSP.Structures.CompletionItem := Value; + begin + -- Return immediately if we don't have data that allows us to compute + -- additional information for the given item. + -- This is the case when all the completion item's fields have already + -- been computed. + if Value.data.Is_Empty then + Self.Sender.On_Completion_Resolve_Response (Id, Value); + return; + end if; + + LSP.GPR_Completions.Fill_Completion_Resolve_Response + (Response => Response); + + Self.Sender.On_Completion_Resolve_Response (Id, Response); + end On_Completion_Resolve_Request; + ---------------------------- -- On_Server_Notification -- ---------------------------- @@ -668,33 +713,6 @@ package body LSP.GPR_Handlers is end if; end Publish_Diagnostics; - ------------- - -- To_File -- - ------------- - - function To_File - (Self : Message_Handler'Class; - Item : LSP.Structures.DocumentUri) return GNATCOLL.VFS.Virtual_File - is - (GNATCOLL.VFS.Create_From_UTF8 - (URIs.Conversions.To_File - (URI => VSS.Strings.Conversions.To_UTF_8_String (Item), - Normalize => Self.Follow_Symlinks))); - - ------------- - -- To_File -- - ------------- - - function To_File - (Self : Message_Handler'Class; - Item : LSP.Structures.DocumentUri) return GPR2.Path_Name.Object - is - (GPR2.Path_Name.Create_File - (GPR2.Filename_Type - (URIs.Conversions.To_File - (URI => VSS.Strings.Conversions.To_UTF_8_String (Item), - Normalize => Self.Follow_Symlinks)))); - ------------------------------------ -- To_Optional_DiagnosticSeverity -- ------------------------------------ @@ -741,15 +759,4 @@ package body LSP.GPR_Handlers is return Result; end To_Range; - ------------ - -- To_URI -- - ------------ - - function To_URI - (Self : Message_Handler'Class; - Item : GPR2.Path_Name.Object) return LSP.Structures.DocumentUri - is - (VSS.Strings.Conversions.To_Virtual_String - (URIs.Conversions.From_File (Item.Value)) with null record); - end LSP.GPR_Handlers; diff --git a/source/gpr/lsp-gpr_handlers.ads b/source/gpr/lsp-gpr_handlers.ads index b8afe5c1c..1d917be41 100644 --- a/source/gpr/lsp-gpr_handlers.ads +++ b/source/gpr/lsp-gpr_handlers.ads @@ -25,6 +25,7 @@ private with GPR2.File_Readers; private with GPR2.Path_Name; with LSP.Client_Message_Receivers; +with LSP.GPR_Client_Capabilities; with LSP.GPR_Documents; with LSP.GPR_Files; with LSP.Server_Message_Visitors; @@ -36,6 +37,10 @@ private with LSP.Structures; with LSP.Tracers; with LSP.Unimplemented_Handlers; +with URIs; + +with VSS.Strings.Conversions; + package LSP.GPR_Handlers is type Message_Handler @@ -84,6 +89,8 @@ private and LSP.GPR_Documents.Document_Provider and LSP.GPR_Files.File_Provider with record + Client : LSP.GPR_Client_Capabilities.Client_Capability; + Open_Documents : Document_Maps.Map; -- The documents that are currently open @@ -146,6 +153,16 @@ private Id : LSP.Structures.Integer_Or_Virtual_String; Value : LSP.Structures.HoverParams); + overriding procedure On_Completion_Request + (Self : in out Message_Handler; + Id : LSP.Structures.Integer_Or_Virtual_String; + Value : LSP.Structures.CompletionParams); + + overriding procedure On_Completion_Resolve_Request + (Self : in out Message_Handler; + Id : LSP.Structures.Integer_Or_Virtual_String; + Value : LSP.Structures.CompletionItem); + ----------------------------------------- -- LSP.GPR_Documents.Document_Provider -- ----------------------------------------- @@ -193,4 +210,30 @@ private (Self : access Message_Handler) return GPR2.File_Readers.File_Reader_Reference is (Self.File_Reader); + overriding function To_File + (Self : access Message_Handler; + Item : LSP.Structures.DocumentUri) return GNATCOLL.VFS.Virtual_File + is + (GNATCOLL.VFS.Create_From_UTF8 + (URIs.Conversions.To_File + (URI => VSS.Strings.Conversions.To_UTF_8_String (Item), + Normalize => Self.Follow_Symlinks))); + + overriding function To_File + (Self : access Message_Handler; + Item : LSP.Structures.DocumentUri) return GPR2.Path_Name.Object + is + (GPR2.Path_Name.Create_File + (GPR2.Filename_Type + (URIs.Conversions.To_File + (URI => VSS.Strings.Conversions.To_UTF_8_String (Item), + Normalize => Self.Follow_Symlinks)))); + + overriding function To_URI + (Self : access Message_Handler; + Item : GPR2.Path_Name.Object) return LSP.Structures.DocumentUri + is + (VSS.Strings.Conversions.To_Virtual_String + (URIs.Conversions.From_File (Item.Value)) with null record); + end LSP.GPR_Handlers; diff --git a/testsuite/ada_lsp/hover.predefined_entities/default.gpr b/testsuite/ada_lsp/hover.predefined_entities/default.gpr new file mode 100644 index 000000000..ee0d3ea36 --- /dev/null +++ b/testsuite/ada_lsp/hover.predefined_entities/default.gpr @@ -0,0 +1,2 @@ +project Default is +end Default; \ No newline at end of file diff --git a/testsuite/ada_lsp/hover.predefined_entities/main.adb b/testsuite/ada_lsp/hover.predefined_entities/main.adb new file mode 100644 index 000000000..a9ebc8069 --- /dev/null +++ b/testsuite/ada_lsp/hover.predefined_entities/main.adb @@ -0,0 +1,10 @@ +with Ada.Text_IO; use Ada.Text_IO; + +procedure Main + with SPARK_Mode => Off +is + Foo : Integer := 30; + pragma Convention (C, Foo); +begin + Put_Line (Foo'Image); +end Main; diff --git a/testsuite/ada_lsp/hover.predefined_entities/test.json b/testsuite/ada_lsp/hover.predefined_entities/test.json new file mode 100644 index 000000000..dfd6c3a99 --- /dev/null +++ b/testsuite/ada_lsp/hover.predefined_entities/test.json @@ -0,0 +1,333 @@ +[ + { + "comment": [ + "This test checks that the textDocument/hover request works fine ", + "on predefined entities (pragmas, aspects, attributes)." + ] + }, + { + "start": { + "cmd": ["${ALS}"] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "id": 1, + "method": "initialize", + "params": { + "processId": 2357134, + "rootUri": "$URI{.}", + "capabilities": { + "workspace": { + "applyEdit": true, + "workspaceEdit": { + "documentChanges": true, + "resourceOperations": ["rename"] + } + }, + "textDocument": { + "synchronization": {}, + "completion": { + "dynamicRegistration": true, + "completionItem": { + "snippetSupport": false, + "documentationFormat": ["plaintext", "markdown"], + "resolveSupport": { + "properties": ["detail", "documentation"] + } + } + }, + "hover": {}, + "signatureHelp": {}, + "declaration": {}, + "definition": {}, + "typeDefinition": {}, + "implementation": {}, + "documentSymbol": { + "hierarchicalDocumentSymbolSupport": true + }, + "codeAction": { + "codeActionLiteralSupport": { + "codeActionKind": { + "valueSet": [ + "", + "quickfix", + "refactor", + "refactor.extract", + "refactor.inline", + "refactor.rewrite", + "source", + "source.organizeImports" + ] + } + } + }, + "formatting": { + "dynamicRegistration": false + }, + "rangeFormatting": { + "dynamicRegistration": false + }, + "onTypeFormatting": { + "dynamicRegistration": false + }, + "publishDiagnostics": { + "relatedInformation": true + }, + "foldingRange": { + "lineFoldingOnly": true + } + }, + "experimental": { + "advanced_refactorings": ["add_parameter"] + } + } + } + }, + "wait": [ + { + "id": 1, + "result": { + "capabilities": { + "textDocumentSync": 2, + "completionProvider": { + "triggerCharacters": [".", ",", "'", "("], + "resolveProvider": true + }, + "hoverProvider": true, + "signatureHelpProvider": { + "triggerCharacters": [",", "("], + "retriggerCharacters": ["\b"] + }, + "declarationProvider": true, + "definitionProvider": true, + "typeDefinitionProvider": true, + "implementationProvider": true, + "referencesProvider": true, + "documentHighlightProvider": true, + "documentSymbolProvider": true, + "codeActionProvider": { + "workDoneProgress": false, + "codeActionKinds": ["quickfix", "refactor.rewrite"], + "resolveProvider": false + }, + "workspaceSymbolProvider": true, + "documentFormattingProvider": true, + "documentRangeFormattingProvider": true, + "documentOnTypeFormattingProvider": { + "firstTriggerCharacter": "\n" + }, + "renameProvider": { + "prepareProvider": true + }, + "foldingRangeProvider": true, + "executeCommandProvider": { + "commands": ["", "als-other-file"] + }, + "callHierarchyProvider": true, + "semanticTokensProvider": { + "legend": { + "tokenTypes": [], + "tokenModifiers": [] + }, + "range": true, + "full": true + }, + "workspace": {}, + "alsReferenceKinds": ["", "reference"] + } + } + } + ] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "method": "initialized" + }, + "wait": [] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "method": "workspace/didChangeConfiguration", + "params": { + "settings": { + "ada": { + "scenarioVariables": {}, + "defaultCharset": "ISO-8859-1", + "enableDiagnostics": false, + "followSymlinks": false, + "documentationStyle": "gnat", + "namedNotationThreshold": 3, + "foldComments": false + } + } + } + }, + "wait": [] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "method": "textDocument/didOpen", + "params": { + "textDocument": { + "uri": "$URI{main.adb}", + "languageId": "Ada", + "version": 0, + "text": "with Ada.Text_IO; use Ada.Text_IO;\n\nprocedure Main \n with SPARK_Mode => Off\nis\n Foo : Integer := 30;\n pragma Convention (C, Foo);\nbegin\n Put_Line (Foo'Image);\nend Main;\n" + } + } + }, + "wait": [] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "id": 4, + "method": "textDocument/hover", + "params": { + "textDocument": { + "uri": "$URI{main.adb}" + }, + "position": { + "line": 3, + "character": 7 + } + } + }, + "wait": [ + { + "id": 4, + "result": { + "contents": [ + { + "language": "ada", + "value": "GNAT RM" + }, + { + "language": "plaintext", + "value": "This aspect is equivalent to *note pragma SPARK_Mode: eb. and may be\nspecified for either or both of the specification and body of a\nsubprogram or package." + } + ] + } + } + ] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "id": 5, + "method": "textDocument/hover", + "params": { + "textDocument": { + "uri": "$URI{main.adb}" + }, + "position": { + "line": 6, + "character": 10 + } + } + }, + "wait": [ + { + "id": 5, + "result": { + "contents": [ + { + "language": "ada", + "value": "Ada RM" + }, + { + "language": "plaintext", + "value": "Syntax:\n\npragma Convention ([Convention=>]convention_identifier,[Entity=>]local_name);" + } + ] + } + } + ] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "id": 6, + "method": "textDocument/hover", + "params": { + "textDocument": { + "uri": "$URI{main.adb}" + }, + "position": { + "line": 8, + "character": 17 + } + } + }, + "wait": [ + { + "id": 6, + "result": { + "contents": [ + { + "language": "ada", + "value": "Ada RM" + }, + { + "language": "plaintext", + "value": "For every scalar subtype S:\n\n\nS'Image denotes a function with the following specification:\n\n\nfunction S'Image(Arg : S'Base)\nreturn String\n\n\nThe function returns an image of the value of Arg as a String.\nSee 3.5." + } + ] + } + } + ] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "method": "textDocument/didClose", + "params": { + "textDocument": { + "uri": "$URI{main.adb}" + } + } + }, + "wait": [] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "id": 7, + "method": "shutdown" + }, + "wait": [ + { + "id": 7, + "result": null + } + ] + } + }, + { + "stop": { + "exit_code": 0 + } + } +] diff --git a/testsuite/ada_lsp/hover.predefined_entities/test.yaml b/testsuite/ada_lsp/hover.predefined_entities/test.yaml new file mode 100644 index 000000000..9ef50e18d --- /dev/null +++ b/testsuite/ada_lsp/hover.predefined_entities/test.yaml @@ -0,0 +1 @@ +title: 'hover.predefined_entities' diff --git a/testsuite/gpr_lsp/completion_attribute_resolve/C b/testsuite/gpr_lsp/completion_attribute_resolve/C new file mode 100644 index 000000000..e69de29bb diff --git a/testsuite/gpr_lsp/completion_attribute_resolve/agg.gpr b/testsuite/gpr_lsp/completion_attribute_resolve/agg.gpr new file mode 100644 index 000000000..20687a90b --- /dev/null +++ b/testsuite/gpr_lsp/completion_attribute_resolve/agg.gpr @@ -0,0 +1,6 @@ +aggregate library project Agg is +for Project_F +for Ext +package Builder is + for S + for E diff --git a/testsuite/gpr_lsp/completion_attribute_resolve/test.json b/testsuite/gpr_lsp/completion_attribute_resolve/test.json new file mode 100644 index 000000000..96a4f2edb --- /dev/null +++ b/testsuite/gpr_lsp/completion_attribute_resolve/test.json @@ -0,0 +1,353 @@ +[ + { + "comment": [ + "completion attributes resolve" + ] + }, + { + "start": { + "cmd": [ + "${ALS}", + "--language-gpr" + ] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "id": 0, + "method": "initialize", + "params": { + "processId": 2243210, + "clientInfo": { + "name": "Visual Studio Code", + "version": "1.63.2" + }, + "rootUri": "$URI{.}", + "capabilities": { + "workspace": { + "applyEdit": true, + "workspaceEdit": { + "documentChanges": true, + "resourceOperations": [ + "create", + "rename", + "delete" + ], + "normalizesLineEndings": true + }, + "didChangeConfiguration": {}, + "didChangeWatchedFiles": {}, + "symbol": {}, + "executeCommand": {}, + "configuration": true, + "workspaceFolders": true, + "fileOperations": { + "dynamicRegistration": true, + "didCreate": true, + "didRename": true, + "didDelete": true, + "willCreate": true, + "willRename": true, + "willDelete": true + } + }, + "textDocument": { + "publishDiagnostics": {}, + "synchronization": {}, + "completion": { + "contextSupport": true, + "completionItem": { + "snippetSupport": true, + "commitCharactersSupport": true, + "documentationFormat": [ + "markdown", + "plaintext" + ], + "deprecatedSupport": true, + "preselectSupport": true, + "tagSupport": { + "valueSet": [ + 1 + ] + }, + "insertReplaceSupport": true, + "resolveSupport": { + "properties": [ + "documentation", + "detail", + "additionalTextEdits" + ] + }, + "insertTextModeSupport": { + "valueSet": [ + 1, + 2 + ] + } + }, + "completionItemKind": { + "valueSet": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25 + ] + } + }, + "documentSymbol": {}, + "codeAction": {} + }, + "window": { + "workDoneProgress": true + } + } + } + }, + "wait": [ + { + "id": 0, + "result": { + "capabilities": { + "textDocumentSync": { + "openClose": true, + "change": 1 + }, + "completionProvider": { + "triggerCharacters": [ + " " + ], + "resolveProvider": true + }, + "hoverProvider": true, + "documentSymbolProvider": {} + } + } + } + ] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "id": 1, + "method": "textDocument/completion", + "params": { + "textDocument": { + "uri": "$URI{agg.gpr}" + }, + "position": { + "line": 1, + "character": 13 + }, + "context": { + "triggerKind": 1 + } + } + }, + "wait": [ + { + "id": 1, + "result": { + "isIncomplete": false, + "items": [ + { + "label": "Project_Files", + "data": [ + "", + "Project_Files" + ] + } + ] + } + } + ] + } + }, + { + "send": { + "request": { + "id": 2, + "method": "completionItem/resolve", + "params": { + "label": "Project_Files", + "insertTextFormat": 1, + "data": [ + "", + "Project_Files" + ] + } + }, + "wait": [ + { + "id": 2, + "result": { + "label": "Project_Files", + "documentation": "Value is the list of aggregated projects.", + "insertTextFormat": 1, + "data": [ + "", + "Project_Files" + ] + } + } + ] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "id": 3, + "method": "textDocument/completion", + "params": { + "textDocument": { + "uri": "$URI{agg.gpr}" + }, + "position": { + "line": 2, + "character": 7 + }, + "context": { + "triggerKind": 1 + } + } + }, + "wait": [ + { + "id": 3, + "result": { + "isIncomplete": false, + "items": [] + } + } + ] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "id": 4, + "method": "textDocument/completion", + "params": { + "textDocument": { + "uri": "$URI{agg.gpr}" + }, + "position": { + "line": 4, + "character": 6 + }, + "context": { + "triggerKind": 1 + } + } + }, + "wait": [ + { + "id": 4, + "result": { + "isIncomplete": false, + "items": [ + { + "label": "Switches", + "data": [ + "Builder", + "Switches" + ] + } + ] + } + } + ] + } + }, + { + "send": { + "request": { + "id": 5, + "method": "completionItem/resolve", + "params": { + "label": "Switches", + "insertTextFormat": 1, + "data": [ + "Builder", + "Switches" + ] + } + }, + "wait": [ + { + "id": 5, + "result": { + "label": "Switches", + "documentation": "Index is either a language name or a source file name. Value is the list of builder switches to be used when building an executable. Index is either the source file name of the executable to be built or its language name.", + "insertTextFormat": 1, + "data": [ + "Builder", + "Switches" + ] + } + } + ] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "id": 6, + "method": "textDocument/completion", + "params": { + "textDocument": { + "uri": "$URI{agg.gpr}" + }, + "position": { + "line": 5, + "character": 6 + }, + "context": { + "triggerKind": 1 + } + } + }, + "wait": [ + { + "id": 6, + "result": { + "isIncomplete": false, + "items": [] + } + } + ] + } + }, + { + "stop": { + "exit_code": 0 + } + } +] \ No newline at end of file diff --git a/testsuite/gpr_lsp/completion_attribute_resolve/test.yaml b/testsuite/gpr_lsp/completion_attribute_resolve/test.yaml new file mode 100644 index 000000000..43e4423a9 --- /dev/null +++ b/testsuite/gpr_lsp/completion_attribute_resolve/test.yaml @@ -0,0 +1 @@ +title: 'attribute completion/resolve test' diff --git a/testsuite/gpr_lsp/completion_package/agg.gpr b/testsuite/gpr_lsp/completion_package/agg.gpr new file mode 100644 index 000000000..e9429acb5 --- /dev/null +++ b/testsuite/gpr_lsp/completion_package/agg.gpr @@ -0,0 +1,4 @@ +aggregate library project Agg is +package +package Bu +package -- diff --git a/testsuite/gpr_lsp/completion_package/test.json b/testsuite/gpr_lsp/completion_package/test.json new file mode 100644 index 000000000..b731863bc --- /dev/null +++ b/testsuite/gpr_lsp/completion_package/test.json @@ -0,0 +1,133 @@ +[ + { + "comment": [ + "package completion (resolve disabled)" + ] + }, + { + "start": { + "cmd": [ + "${ALS}", + "--language-gpr" + ] + } + }, + { + "send": { + "request": { + "params": { + "capabilities": {}, + "rootUri": "$URI{.}" + }, + "id": 1, + "method": "initialize" + }, + "wait": [ + { + "id": 1, + "result": { + "capabilities": { + "textDocumentSync": { + "openClose": true, + "change": 1 + }, + "documentSymbolProvider": {} + } + } + } + ] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "method": "initialized" + }, + "wait": [] + } + }, + { + "send": { + "request": { + "params": { + "textDocument": { + "text": "aggregate library project Agg is\npackage \npackage Bu\npackage -- \n", + "version": 0, + "uri": "$URI{agg.gpr}", + "languageId": "Gpr" + } + }, + "jsonrpc": "2.0", + "method": "textDocument/didOpen" + }, + "wait": [ + { + "method": "textDocument/publishDiagnostics", + "params": { + "uri": "$URI{agg.gpr}", + "diagnostics": [ + { + "range": { + "start": { + "line": 2, + "character": 0 + }, + "end": { + "line": 2, + "character": 0 + } + }, + "severity": 1, + "message": "Expected Identifier, got 'package'" + } + ] + } + } + ] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "id": 2, + "method": "textDocument/completion", + "params": { + "textDocument": { + "uri": "$URI{agg.gpr}" + }, + "position": { + "line": 2, + "character": 10 + }, + "context": { + "triggerKind": 1 + } + } + }, + "wait": [ + { + "id": 2, + "result": { + "isIncomplete": false, + "items": [ + { + "label": "Builder", + "documentation": "This package specifies the compilation options used when building an executable or a library for a project. Most of the options should be set in one of Compiler, Binder or Linker packages, but there are some general options that should be defined in this package.", + "data": [ + "Builder" + ] + } + ] + } + } + ] + } + }, + { + "stop": { + "exit_code": 0 + } + } +] diff --git a/testsuite/gpr_lsp/completion_package/test.yaml b/testsuite/gpr_lsp/completion_package/test.yaml new file mode 100644 index 000000000..fa4f4df45 --- /dev/null +++ b/testsuite/gpr_lsp/completion_package/test.yaml @@ -0,0 +1 @@ +title: 'package completion (resolve disabled) test' diff --git a/testsuite/gpr_lsp/completion_package_resolve/agg.gpr b/testsuite/gpr_lsp/completion_package_resolve/agg.gpr new file mode 100644 index 000000000..e9429acb5 --- /dev/null +++ b/testsuite/gpr_lsp/completion_package_resolve/agg.gpr @@ -0,0 +1,4 @@ +aggregate library project Agg is +package +package Bu +package -- diff --git a/testsuite/gpr_lsp/completion_package_resolve/test.json b/testsuite/gpr_lsp/completion_package_resolve/test.json new file mode 100644 index 000000000..66f9e38b8 --- /dev/null +++ b/testsuite/gpr_lsp/completion_package_resolve/test.json @@ -0,0 +1,587 @@ +[ + { + "comment": [ + "package completion/resolve" + ] + }, + { + "start": { + "cmd": [ + "${ALS}", + "--language-gpr" + ] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "id": 0, + "method": "initialize", + "params": { + "processId": 2243210, + "clientInfo": { + "name": "Visual Studio Code", + "version": "1.63.2" + }, + "rootUri": "$URI{.}", + "capabilities": { + "workspace": { + "applyEdit": true, + "workspaceEdit": { + "documentChanges": true, + "resourceOperations": [ + "create", + "rename", + "delete" + ], + "normalizesLineEndings": true + }, + "didChangeConfiguration": {}, + "didChangeWatchedFiles": {}, + "symbol": {}, + "executeCommand": {}, + "configuration": true, + "workspaceFolders": true, + "fileOperations": { + "dynamicRegistration": true, + "didCreate": true, + "didRename": true, + "didDelete": true, + "willCreate": true, + "willRename": true, + "willDelete": true + } + }, + "textDocument": { + "publishDiagnostics": {}, + "synchronization": {}, + "completion": { + "contextSupport": true, + "completionItem": { + "snippetSupport": true, + "commitCharactersSupport": true, + "documentationFormat": [ + "markdown", + "plaintext" + ], + "deprecatedSupport": true, + "preselectSupport": true, + "tagSupport": { + "valueSet": [ + 1 + ] + }, + "insertReplaceSupport": true, + "resolveSupport": { + "properties": [ + "documentation", + "detail", + "additionalTextEdits" + ] + }, + "insertTextModeSupport": { + "valueSet": [ + 1, + 2 + ] + } + }, + "completionItemKind": { + "valueSet": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25 + ] + } + }, + "documentSymbol": {}, + "codeAction": {} + }, + "window": { + "workDoneProgress": true + } + } + } + }, + "wait": [ + { + "id": 0, + "result": { + "capabilities": { + "textDocumentSync": { + "openClose": true, + "change": 1 + }, + "completionProvider": { + "triggerCharacters": [ + " " + ], + "resolveProvider": true + }, + "hoverProvider": true, + "documentSymbolProvider": {} + } + } + } + ] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "method": "initialized", + "params": {} + }, + "wait": [] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "method": "workspace/didChangeConfiguration", + "params": { + "settings": { + "ada": { + "scenarioVariables": {}, + "enableDiagnostics": false, + "defaultCharset": "ISO-8859-1" + } + } + } + }, + "wait": [] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "id": 4, + "method": "textDocument/completion", + "params": { + "textDocument": { + "uri": "$URI{agg.gpr}" + }, + "position": { + "line": 1, + "character": 7 + }, + "context": { + "triggerKind": 1 + } + } + }, + "wait": [ + { + "id": 4, + "result": { + "isIncomplete": false, + "items": [] + } + } + ] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "id": 5, + "method": "textDocument/completion", + "params": { + "textDocument": { + "uri": "$URI{agg.gpr}" + }, + "position": { + "line": 2, + "character": 8 + }, + "context": { + "triggerKind": 1 + } + } + }, + "wait": [ + { + "id": 5, + "result": { + "isIncomplete": false, + "items": [] + } + } + ] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "id": 6, + "method": "textDocument/completion", + "params": { + "textDocument": { + "uri": "$URI{agg.gpr}" + }, + "position": { + "line": 2, + "character": 9 + }, + "context": { + "triggerKind": 1 + } + } + }, + "wait": [ + { + "id": 6, + "result": { + "isIncomplete": false, + "items": [] + } + } + ] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "id": 7, + "method": "textDocument/completion", + "params": { + "textDocument": { + "uri": "$URI{agg.gpr}" + }, + "position": { + "line": 3, + "character": 9 + }, + "context": { + "triggerKind": 1 + } + } + }, + "wait": [ + { + "id": 7, + "result": { + "isIncomplete": false, + "items": [] + } + } + ] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "id": 8, + "method": "textDocument/completion", + "params": { + "textDocument": { + "uri": "$URI{agg.gpr}" + }, + "position": { + "line": 3, + "character": 10 + }, + "context": { + "triggerKind": 1 + } + } + }, + "wait": [ + { + "id": 8, + "result": { + "isIncomplete": false, + "items": [] + } + } + ] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "id": 9, + "method": "textDocument/completion", + "params": { + "textDocument": { + "uri": "$URI{agg.gpr}" + }, + "position": { + "line": 3, + "character": 11 + }, + "context": { + "triggerKind": 1 + } + } + }, + "wait": [ + { + "id": 9, + "result": { + "isIncomplete": false, + "items": [] + } + } + ] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "id": 10, + "method": "textDocument/completion", + "params": { + "textDocument": { + "uri": "$URI{agg.gpr}" + }, + "position": { + "line": 2, + "character": 10 + }, + "context": { + "triggerKind": 1 + } + } + }, + "wait": [ + { + "id": 10, + "result": { + "isIncomplete": false, + "items": [ + { + "label": "Builder", + "data": [ + "Builder" + ] + } + ] + } + } + ] + } + }, + { + "send": { + "request": { + "id": 11, + "method": "completionItem/resolve", + "params": { + "label": "Builder", + "insertTextFormat": 1, + "data": [ + "Builder" + ] + } + }, + "wait": [ + { + "id": 11, + "result": { + "label": "Builder", + "documentation": "This package specifies the compilation options used when building an executable or a library for a project. Most of the options should be set in one of Compiler, Binder or Linker packages, but there are some general options that should be defined in this package.", + "insertTextFormat": 1, + "data": [ + "Builder" + ] + } + } + ] + } + }, + { + "send": { + "request": { + "jsonrpc": "2.0", + "id": 12, + "method": "textDocument/completion", + "params": { + "textDocument": { + "uri": "$URI{agg.gpr}" + }, + "position": { + "line": 1, + "character": 8 + }, + "context": { + "triggerKind": 1 + } + } + }, + "wait": [ + { + "id": 12, + "result": { + "isIncomplete": false, + "items": [ + { + "label": "Builder", + "data": [ + "Builder" + ] + }, + { + "label": "Clean", + "data": [ + "Clean" + ] + }, + { + "label": "Gnatls", + "data": [ + "Gnatls" + ] + }, + { + "label": "Install", + "data": [ + "Install" + ] + }, + { + "label": "Remote", + "data": [ + "Remote" + ] + }, + { + "label": "Pretty_Printer", + "data": [ + "Pretty_Printer" + ] + }, + { + "label": "Ide", + "data": [ + "Ide" + ] + }, + { + "label": "Ant", + "data": [ + "Ant" + ] + }, + { + "label": "Make", + "data": [ + "Make" + ] + }, + { + "label": "Analyzer", + "data": [ + "Analyzer" + ] + }, + { + "label": "Check", + "data": [ + "Check" + ] + }, + { + "label": "Codepeer", + "data": [ + "Codepeer" + ] + }, + { + "label": "Coverage", + "data": [ + "Coverage" + ] + }, + { + "label": "Dsa", + "data": [ + "Dsa" + ] + }, + { + "label": "Documentation", + "data": [ + "Documentation" + ] + }, + { + "label": "Emulator", + "data": [ + "Emulator" + ] + }, + { + "label": "Gnattest", + "data": [ + "Gnattest" + ] + }, + { + "label": "Prove", + "data": [ + "Prove" + ] + }, + { + "label": "Qgen", + "data": [ + "Qgen" + ] + }, + { + "label": "Stack", + "data": [ + "Stack" + ] + }, + { + "label": "Stub", + "data": [ + "Stub" + ] + } + ] + } + } + ] + } + }, + { + "stop": { + "exit_code": 0 + } + } +] \ No newline at end of file diff --git a/testsuite/gpr_lsp/completion_package_resolve/test.yaml b/testsuite/gpr_lsp/completion_package_resolve/test.yaml new file mode 100644 index 000000000..d3732ccec --- /dev/null +++ b/testsuite/gpr_lsp/completion_package_resolve/test.yaml @@ -0,0 +1 @@ +title: 'package completion/resolve test'